Why am I allowed to call a non-constant member function from const_iterator if the container element is a pointer?

Consider the following code:

#include <vector> using namespace std; struct foo { void bar() { } }; int main() { { vector<foo*> a; a.push_back(new foo()); a.push_back(new foo()); a.push_back(new foo()); vector<foo*>::const_iterator itr = a.begin(); (*itr)->bar(); // compiles - this becomes more confusing // when found in a const method. On first // glance, one will (or at least me) may // assume that bar() must be const if the // method where it is being called from is // const // The above compiles because internally, this is what happens // (ignore the fact that the pointer has not been newd) foo* const * element; (*element)->bar(); // compiles // What I would expect however (maybe it is just me) is for const_iterator // to behave something like this const foo* const_element; const_element->bar(); // compile error } { vector<foo> a; a.resize(10); vector<foo>::const_iterator itr = a.begin(); itr->bar(); // compile error } } 

I understand why this can be called. const_iterator stores the constant as follows: const T* , which for the pointer translates to foo* const * and for the object foo const * .

So my question is: why are we allowed to call the non-const member function from const_iterator ? Isn’t it more intuitive not to allow the call to the non-const member function of const_iterator ? Doesn't iterator design with const parameter prevent this behavior?

A more important question is this: What if I want const_iterator prohibit calling non-constant member functions of a specified object?

+4
source share
3 answers

Should this behavior of the iterator constructor with the const option be prevented?

This is true. You just expect it to be a different operation.

As you discovered, the pointer container ... contains pointers, not objects. Therefore, a const_iterator for such pointers means that pointers are constant and not the objects that they point to.

This will not change, and should not. Standard library containers are typically designed to house full-featured objects, not pointers. Therefore, they should not encourage users to make vector pointers and other dubious constructs.

If you really need a vector to contain pointers, then you should use a container that is actually designed for that. Like acceleration pointer container classes . Their const_iterators correctly bind objects to const . They also do other useful things, such as their own objects that they point to (so that they are deleted correctly), etc.

+5
source

You have a vector of pointers, pointers do not have member functions, so you do not call a member function for what is stored in the vector.

The type of object that you get when dereferencing a pointer depends on the type of that pointer. Your vector is a vector of non-constant pointers, so when you remove a pointer from your container, you always get a non-constant reference to the object with a pointer to the object.

If you need a pointer vector, you have two options. You can create a vector<const foo*> instead, and you can never get a non-constant link to any pointer to an object or, if you need to get non-constant links from non-constant instances of your vector, you will need to create an object that contains the vector as a variable private member, and gives you the access you want through the pass-through interface.

If your vector must own objects to which it has pointers, you can consider a simple vector<foo> instead, or if dynamic allocation is required, boost::ptr_vector<foo> .

+2
source

So my question is: why are we allowed to call a non-constant member function from const_iterator?

"Constant iterator" means that the container element is constant. This does not mean that if this element is a pointer, then the specified object is also constant.

What if I want const_iterator to prohibit calling non-constant member functions of a specified object?

I would not want you to use raw pointers like this, but if you really need to, make it a container of pointers to const objects.

 std::vector<const foo*> a; // ... auto itr = a.cbegin(); (*itr)->bar(); // Compiler error (calling a non-const method on const object). 

Of course, in this case, the following would also be prohibited:

 std::vector<const foo*> a; // ... auto itr = a.begin(); (*itr)->bar(); // Compiler error. 
+1
source

All Articles