Category: iterators | Component type: concept |
X | A type that is a model of Output Iterator |
x, y | Object of type X |
If x is an Output Iterator of type X, then the expression *x = t; stores the value t into x. Note that operator=, like other C++ functions, may be overloaded; it may, in fact, even be a template function. In general, then, t may be any of several different types. A type T belongs to the set of value types of X if, for an object t of type T, *x = t; is well-defined and does not require performing any non-trivial conversions on t. [1]
An Output Iterator may be singular, meaning that the results of most operations, including copying and dereference assignment, are undefined. The only operation that is guaranteed to be supported is assigning a nonsingular iterator to a singular iterator.
An Output Iterator may be dereferenceable, meaning that assignment through it is defined. Dereferenceable iterators are always nonsingular, but nonsingular iterators are not necessarily dereferenceable.
Name | Expression | Type requirements | Return type |
---|---|---|---|
Default constructor |
X x; X() |
||
Copy constructor | X(x) | X | |
Copy constructor | X y(x); or X y = x; | ||
Dereference assignment | *x = t | t is convertible to a type in the set of value types of X. [1] | Result is not used |
Preincrement | ++x | X& | |
Postincrement | (void) x++ | void | |
Postincrement and assign | x++ = t; | Result is not used |
Name | Expression | Precondition | Semantics | Postcondition |
---|---|---|---|---|
Default constructor |
X x; X() |
x may be singular | ||
Copy constructor | X(x) | x is nonsingular | *X(x) = t is equivalent to *x = t [2] | |
Copy constructor | X x(y); or X x = y; | x is nonsingular | *y = t is equivalent to *x = t [2] | |
Dereference assignment | *x = t | x is dereferenceable. If there has been a previous assignment through x, then there has been an intervening increment. [3] | ||
Preincrement | ++x | x is dereferenceable. x has previously been assigned through. If x has previously been incremented, then there has been an intervening assignment through x [3] [4] | x points to the next location into which a value may be stored | |
Postincrement | (void) x++ | x is dereferenceable. x has previously been assigned through. | Equivalent to (void) ++x | x points to the next location into which a value may be stored |
Postincrement and assign | *x++ = t; | x is dereferenceable. If there has been a previous assignment through x, then there has been an intervening increment. [3] [4] | Equivalent to {*x = t; ++x; } | x points to the next location into which a value may be stored |
[1] Other iterator types, including Trivial Iterator and Input Iterator, define the notion of a value type, the type returned when an iterator is dereferenced. This notion does not apply to Output Iterators, however, since the dereference operator (unary operator*) does not return a usable value for Output Iterators. The only context in which the dereference operator may be used is assignment through an output iterator: *x = t. Although Input Iterators and output iterators are roughly symmetrical concepts, there is an important sense in which accessing and storing values are not symmetrical: for an Input Iterator operator* must return a unique type, but, for an Output Iterator, in the expression *x = t, there is no reason why operator= must take a unique type. [5] Consequently, there need not be any unique "value type" for Output Iterators.
[2] There should be only one active copy of a single Output Iterator at any one time. That is: after creating and using a copy x of an Output Iterator y, the original output iterator y should no longer be used.
[3] Assignment through an Output Iterator x is expected to alternate with incrementing x, and there must be an assignment through x before x is ever incremented. Any other order of operations results in undefined behavior. That is: {*x = t; ++x; *x = t2; ++x} is acceptable, but {*x = t; ++x; ++x; *x = t2;} is not.
[4] Note that an Output Iterator need not define comparison for equality. Even if an operator== is defined, x == y need not imply ++x == ++y.
[5] If you are implementing an Output Iterator class X, one sensible way to define *x = t is to define X::operator*() to return an object of some private class X_proxy, and then to define X_proxy::operator=. Note that you may overload X_proxy::operator=, or even define it as a member template; this allows assignment of more than one type through Output Iterators of class X.