What is an iterator's default value?
By convention a "NULL iterator" for containers, which is used to indicate no result, compares equal to the result of container.end()
.
std::vector<X>::iterator iter = std::find(my_vec.begin(), my_vec.end(), x);
if (iter == my_vec.end()) {
//no result found; iter points to "nothing"
}
However, since a default-constructed container iterator is not associated with any particular container, there is no good value it could take. Therefore it is just an uninitialized variable and the only legal operation to do with it is to assign a valid iterator to it.
std::vector<X>::iterator iter; //no particular value
iter = some_vector.begin(); //iter is now usable
For other kinds of iterators this might not be true. E.g in case of istream_iterator
, a default-constructed iterator represents (compares equal to) an istream_iterator
which has reached the EOF of an input stream.
Understanding iterator default value
Why does the iterator returns the default value twice?
The iterator returns the default value as many times at it is called, not only twice. The problem occurs because you defined x
and w
as follows:
x = iter(range(3))
y = iter(range(3))
w = ([next(y, "a"), next(y, "b")] for z in x)
Your w
list has 3 entries (it iterates over the 3 elements in x
), and when you call next(w)
a fourth time, it throws an exception. Try setting x = iter(range(5))
, and you will see that you can now call print(next(w))
5 times. The inner next
calls will return the default values as many times as called.
To confirm this, just output w
after creating it, so you can see its contents:
x = iter(range(3))
y = iter(range(3))
w = ([next(y, "a"), next(y, "b")] for z in x)
list(w)
> [[0, 1], [2, 'b'], ['a', 'b']]
Can I initialize an iterator with null, and if not why?
No, in general you cannot initialize an iterator with NULL
. The iterator requirements do not require an iterator to be assignable or initializable from either an integer type or std::nullptr_t
, the possible types that NULL
can have.
There is no point in trying to do that. It is simply not needed. But since you have not explained why you would try to do that, I can't really make any further suggestions.
Regarding your further questions in the comments: You can value-initialize every forward iterator:
vector<int>::iterator it{}; // value-initialized
Since C++14 you are guaranteed that comparing iterators of the same type constructed in this way compare equal.
All container iterators are forward iterators.
Rust optional iterator default value
It depends whether x
should be an Iterator
or a Vec
.
Iterator
let x = i.into_iter().flatten().chain(iter::repeat(None)).take(3);
Here's every step explained:
into_iter()
creates an iterator from ourOption
. Ournext()
call would return the wholeVec
.flatten
iterates theVec
and thus all its elementschain(iter::repeat(None))
adds unlimitedNone
s to the iterationtake(3)
limits the total amount of elements to three.
However, this assumes that you want to have exactly three elements always and either limit the Vec
or fill it up with None
s.
Vec
Since take(3)
returns an iterator, but unwrap_or
returns a Vec
on an existing vector, we need to transform the iterator into a Vec
via collect()
:
let x = i.unwrap_or(iter::repeat(None).take(3).collect());
Now the types match.
Using iter on a list with a default value
The Pythonic way would usually be to use a for loop:
for val in foo:
print(val)
or if that doesn't work, put the default value in the next
call instead of attaching it to the iterator itself:
bar = iter(foo)
val = next(bar, "default")
If you really want to do this in the iterator, you can use itertools.chain
to chain your iterator with an infinite sequence of your sentinel value:
from itertools import chain, repeat
bar = chain(foo, repeat("default"))
To skip over elements inside a for loop, you could:
bar = iter(foo)
for val in bar:
if_some_condition():
next(bar) # skips over the next iteration of the loop
Default value for next element in Python iterator if iterator is empty?
next
accepts a default value:
next(...)
next(iterator[, default])
Return the next item from the iterator. If default is given and the iterator
is exhausted, it is returned instead of raising StopIteration.
and so
>>> print next(i for i in range(10) if i**2 == 9)
3
>>> print next(i for i in range(10) if i**2 == 17)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> print next((i for i in range(10) if i**2 == 17), None)
None
Note that you have to wrap the genexp in the extra parentheses for syntactic reasons, otherwise:
>>> print next(i for i in range(10) if i**2 == 17, None)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
C++ using default-initialized iterators to create an empty std::string
According to cppreference.com, a random access iterator, of which a string iterator is one, meets all requirements of a bidirectional iterator.
Furthermore, a bidirectional iterator meets all requirements of a forward iterator.
Finally, since C++14, a forward iterator can be value-initialized, and will compare equal to all other value-initialized forward iterators of the same type:
A value-initialized LegacyForwardIterator behaves like the
past-the-end iterator of some unspecified empty container: it compares
equal to all value-initialized LegacyForwardIterators of the same
type.
Based on that, I believe this is well-defined at least as of C++14.
How to check if the iterator is initialized?
I managed to find this in the current standard (c++03 ). 24.1 p 5 tells :
Just as a regular pointer to an array guarantees that there is a
pointer value pointing past the last element of the array, so for any
iterator type there is an iterator value that points past the last
element of a corresponding container. These values are called
past-the-end values. Values of an iterator i for which the expression
*i
is defined are called dereferenceable. The library never assumes
that past-the-end values are dereferenceable. Iterators can also have
singular values that are not associated with any container. [Example:
After the declaration of an uninitialized pointerx
(as withint* x;
),
x
must always be assumed to have a singular value of a pointer. ]
Results of most expressions are undefined for singular values; the
only exception is an assignment of a non-singular value to an iterator
that holds a singular value. In this case the singular value is
overwritten the same way as any other value. Dereferenceable values
are always non- singular.
(Emphasis mine)
So the answer is : no, it is not possible.
Comparing default-constructed iterators with operator==
OK, I'll take a stab. The C++ Standard, Section 24.1/5:
Iterators can also have singular
values that are not associated with
any container. [Example: After the
declaration of an uninitialized
pointer x (as with int* x;), x must
always be assumed to have a singular
value of a pointer. ] Results of most
expressions are undefined for singular
values; the only excep- tion is an
assignment of a non-singular value to
an iterator that holds a singular
value.
So, no, they can't be compared.
NULL/default value for Template vector typename iterators
wish to initialize them to a fixed default value. In the case of pointers, I would have initialized to NULL, not sure what should be done for vector iterators.
There is no such thing for std::vector::iterator
. Instances of std::vector::iterator
are not sensible unless they are associated with a std::vector
.
You can leave your std::vector::iterator
default initialized but then you cannot use it unless it is set to a suitable value that is associated with an instance of std::vector
.
Related Topics
Issuing System Commands in Linux from C, C++
What Does '<Cuchar>' Provide, and Where Is It Documented
Multi-Threading Benchmarking Issues
Why Floating Point Value Such as 3.14 Are Considered as Double by Default in Msvc
In C++ , What's So Special About "_Move_H"
Why Can't I Write to a String Literal While I *Can* Write to a String Object
Why Stdfax.H Should Be the First Include on Mfc Applications
C++ Qt Signal and Slot Not Firing
Why Does Gcc Generate 15-20% Faster Code If I Optimize for Size Instead of Speed
Child Process Receives Parent's Sigint
Constexpr Static Member Before/After C++17