Opened 12 years ago

Closed 12 years ago

Last modified 12 years ago

#5463 closed Bugs (invalid)

default constructor of filter_iterator does not initialize members

Reported by: aleksander.sulkowski@… Owned by: Dave Abrahams
Milestone: To Be Determined Component: iterator
Version: Boost 1.47.0 Severity: Problem
Keywords: filter_iterator default constructor Cc:

Description

filter_iterator initializes neither m_predicate nor m_end in its default constructor. Not initializing m_end in case when it is a pointer (or any other built in type) results in a random bahavior of end() method.

Change History (5)

comment:1 by Steven Watanabe, 12 years ago

Resolution: invalid
Status: newclosed

A default constructed filter iterator is considered singular. You should not expect to do anything with it, any more than you can expect a default constructed pointer to behave in a useful way.

comment:2 by anonymous, 12 years ago

2 default constructed pointers are equal (if they are initialized). Why wouldn't iterators be? The current iterator behavior changes between different compilers/modes. Make the constructor private if you do not want it to be used. Making it not deterministic is not helping. Why would one expose a nondeterministic method?

Is there any argument why not to initialize members of the iterator?

comment:3 by Dave Abrahams, 12 years ago

A pointer can't be both default constructed and initialized, by definition. The default constructor is deterministic if you only do the things allowed with singular iterators: assign-to-them and destroy-them. There is an efficiency argument for not initializing members, and besides, the default constructed members that are themselves iterators would still be singular, so in the generic case, it wouldn't help you.

comment:4 by anonymous, 12 years ago

There is one more additional use of singular iterators - like in case of istream_iterator. They can be compared with an other iterator to check agains end condition. It may be far more useful then calling "end" method from the iterator class. Please read my example below.

I do not agree with the efficiency argument, as only if the iterator encapsulated by filter_iterator is a class, it's constructor is called anyway. I do not think simple types initialization cost justifies leaving it uninitialized.

It would help in my particular case. I have an iterator encapsulating a filter_iterator on top of a predicate and an array. I relay on the fact the instances of my iterator default constructed are equal. I pass to boost::minmax 2 arguments:

  • a non-default constructed instance of my iterator, initialized with the filter iterator initialized with an array.
  • a default constructed iterator, what encapsulates default constructed filter iterator which indicates the end (like in istream_iterator)

I check result of minmax, that returns a pair of iterators having my type. In order to check if they are end iterators, I compare each with default constructed iterator. I do not have access to "internal", filter_iterator anymore, but I can construct a new "end iterator" and compare.

It will work, only if encapsulated filter iterators, default initialized, will be equal to the "end" iterator I passed to boost::minmax. In order to achieve that filter iterators have to be equal, so the iterator they encapsulate have to be initialized (to be equal). And they are for any other than simple type case.

in reply to:  4 comment:5 by Dave Abrahams, 12 years ago

Replying to anonymous:

There is one more additional use of singular iterators - like in case of istream_iterator. They can be compared with an other iterator to check agains end condition.

No, please consult the standard. Singular iterators can't be compared.

For that particular iterator type, default-construction does not produce a singular iterator.

It may be far more useful then calling "end" method from the iterator class.

“"end" method?”

Please read my example below.

I do not agree with the efficiency argument, as only if the iterator encapsulated by filter_iterator is a class, it's constructor is called anyway. I do not think simple types initialization cost justifies leaving it uninitialized.

Probably it doesn't in your application and in many others, but libraries have broad constituencies.

It would help in my particular case. I have an iterator encapsulating a filter_iterator on top of a predicate and an array. I relay on the fact the instances of my iterator default constructed are equal. I pass to boost::minmax 2 arguments:

  • a non-default constructed instance of my iterator, initialized with the filter iterator initialized with an array.
  • a default constructed iterator, what encapsulates default constructed filter iterator which indicates the end (like in istream_iterator)

I check result of minmax, that returns a pair of iterators having my type. In order to check if they are end iterators, I compare each with default constructed iterator. I do not have access to "internal", filter_iterator anymore,

The .base() member function doesn't work for this purpose?

but I can construct a new "end iterator" and compare.

It will work, only if encapsulated filter iterators, default initialized, will be equal to the "end" iterator I passed to boost::minmax. In order to achieve that filter iterators have to be equal, so the iterator they encapsulate have to be initialized (to be equal). And they are for any other than simple type case.

I'm sorry, I can't understand what you're describing well enough. Perhaps if you attached some code...

Note: See TracTickets for help on using tickets.