potential problem with indirect_iterator (GCC 3.3.2)

I sent this a couple days ago, but I think it became lost in the ether when the list moved machines.... apologies if it didn't. I noticed a small potential problem with indirect_iterator. I've been using it with raw pointers, and the default constructor appears broken in this case (gcc-3.3.2): #include <boost/iterator/indirect_iterator.hpp> #include <iostream> struct MyType {}; typedef MyType* MyTypeList; typedef boost::indirect_iterator< MyTypeList, MyType > Iter; int main( int argc, char** argv ) { std::cout << "Iter() == Iter() ? " << ( Iter() == Iter() ) << std::endl << "Iter(NULL) == Iter(NULL) ? " << ( Iter(NULL) == Iter(NULL) ) << std::endl; } The output is: Iter() == Iter() ? 0 Iter(NULL) == Iter(NULL) ? 1 Is this an actual bug, or am I misusing the code? If I'm misusing the code, is there some reason for this? It's inconvenient that the default constructor doesn't initialize pointers to some consistent value; the problem goes away when I change the indirect_iterator default constructor: 94c94,96 < indirect_iterator() {} --- > indirect_iterator() > : super_t( Iterator() ) > {} Best, -- Shannon Stewman | Let us walk through the waning night, Caught in a whirlpool, | As dawn-rays tickle our toes, the dew soothes A quartering act: | Our blistered soles, and damp bones stir Solitude or society? | As crimson cracks under the blue-grey sky.

On Mon, 1 Mar 2004 21:39:39 -0600, Shannon Stewman <stew@uchicago.edu> wrote:
I sent this a couple days ago, but I think it became lost in the ether when the list moved machines.... apologies if it didn't.
I noticed a small potential problem with indirect_iterator. I've been using it with raw pointers, and the default constructor appears broken in this case (gcc-3.3.2):
#include <boost/iterator/indirect_iterator.hpp> #include <iostream>
struct MyType {}; typedef MyType* MyTypeList; typedef boost::indirect_iterator< MyTypeList, MyType > Iter;
int main( int argc, char** argv ) { std::cout << "Iter() == Iter() ? " << ( Iter() == Iter() ) << std::endl
That's UB - uninitialized iterators (and in this case pointers) can't be compared.
<< "Iter(NULL) == Iter(NULL) ? " << ( Iter(NULL) == Iter(NULL) ) << std::endl; }
The output is:
Iter() == Iter() ? 0 Iter(NULL) == Iter(NULL) ? 1
Is this an actual bug, or am I misusing the code?
(Almost) all iterators must be initialized. I think the only standard iterators with a well defined default state are the stream iterators. Many iterator types have no "default" state - what is an iterator pointing to when in this default state? What container is it associated with? It is an invalid iterator, so you can't do anything with it anyway (including comparing it to another iterator). e.g. if I had a debug vector iterator, I might do: iterator() :p(0) { } //... bool operator==(iterator lhs, iterator rhs) { assert (lhs.p != 0); assert (rhs.p != 0); return lhs.p == rhs.p; }
If I'm misusing the code, is there some reason for this? It's inconvenient that the default constructor doesn't initialize pointers to some consistent value; the problem goes away when I change the indirect_iterator default constructor:
94c94,96 < indirect_iterator() {} ---
indirect_iterator() : super_t( Iterator() ) {}
That gives you a false sense of safety. Default initializing many iterator types is a no-op - they are still unusable (e.g. std::list::iterator). Tom -- C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

Tom Widmer <tom_usenet@hotmail.com> writes:
If I'm misusing the code, is there some reason for this? It's inconvenient that the default constructor doesn't initialize pointers to some consistent value; the problem goes away when I change the indirect_iterator default constructor:
94c94,96 < indirect_iterator() {} ---
indirect_iterator() : super_t( Iterator() ) {}
That gives you a false sense of safety. Default initializing many iterator types is a no-op - they are still unusable (e.g. std::list::iterator).
or, in the same way, int*. Tom's right. You don't have a right to expect very much from a default-constructed iterator. You can't even copy it without inducing undefined behavior. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Tue, 02 Mar 2004 09:23:36 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Tom Widmer <tom_usenet@hotmail.com> writes:
If I'm misusing the code, is there some reason for this? It's inconvenient that the default constructor doesn't initialize pointers to some consistent value; the problem goes away when I change the indirect_iterator default constructor:
94c94,96 < indirect_iterator() {} ---
indirect_iterator() : super_t( Iterator() ) {}
That gives you a false sense of safety. Default initializing many iterator types is a no-op - they are still unusable (e.g. std::list::iterator).
or, in the same way, int*.
Default initializing an int* isn't a no-op, and you can equality compare such int*s. The same isn't true for std::list::iterator, which is why I chose it. e.g. It i = It(); It j = It(); bool b = (i == j); That's well defined for It=int* (and It=istream_iterator<T>), but UB for It=std::list<int>::iterator (since i and j are singular). Tom -- C++ FAQ: http://www.parashift.com/c++-faq-lite/ C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

Tom Widmer <tom_usenet@hotmail.com> writes:
On Tue, 02 Mar 2004 09:23:36 -0500, David Abrahams <dave@boost-consulting.com> wrote:
Tom Widmer <tom_usenet@hotmail.com> writes:
If I'm misusing the code, is there some reason for this? It's inconvenient that the default constructor doesn't initialize pointers to some consistent value; the problem goes away when I change the indirect_iterator default constructor:
94c94,96 < indirect_iterator() {} ---
indirect_iterator() : super_t( Iterator() ) {}
That gives you a false sense of safety. Default initializing many iterator types is a no-op - they are still unusable (e.g. std::list::iterator).
or, in the same way, int*.
Default initializing an int* isn't a no-op, and you can equality compare such int*s. The same isn't true for std::list::iterator, which is why I chose it.
e.g. It i = It(); It j = It(); bool b = (i == j);
That's well defined for It=int* (and It=istream_iterator<T>), but UB for It=std::list<int>::iterator (since i and j are singular).
Right; I misread your point. I meant: int* p1; int* p2; bool b = (p1 == p2); // undefined behavior Same thing if we replace the int* by std::list::iterator. I guess std::list::iterator is a bit worse in some sense because of the point you're making. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Tue, Mar 02, 2004 at 09:23:36AM -0500, David Abrahams wrote:
Tom's right. You don't have a right to expect very much from a default-constructed iterator. You can't even copy it without inducing undefined behavior.
Thanks for clarifying this. Best, -- Shannon Stewman | Let us walk through the waning night, Caught in a whirlpool, | As dawn-rays tickle our toes, the dew soothes A quartering act: | Our blistered soles, and damp bones stir Solitude or society? | As crimson cracks under the blue-grey sky.
participants (3)
-
David Abrahams
-
Shannon Stewman
-
Tom Widmer