Reputation: 21496
Does const vector<A>
mean that its elements are const
as well?
In the code below,
v[0].set (1234);
in void g ( const vector<A> & v )
produces the compiler error
const.cpp:28:3: error: member function 'set' not viable: 'this' argument has type 'const value_type' (aka 'const A'), but function is not marked const
Why?
But (*v[0]).set(1234);
in void h ( const vector<A *> & v )
is OK for the compiler.
What's the difference between the versions?
// ...........................................................
class A {
private:
int a;
public:
A (int a_) : a (a_) { }
int get () const { return a; }
void set (int a_) { a = a_; }
};
// ...........................................................
void g ( const vector<A> & v ) {
cout << v[0].get();
v[0].set (1234);
} // ()
// ...........................................................
void h ( const vector<A *> & v ) {
cout << (*v[0]).get();
(*v[0]).set(1234);
} // ()
Upvotes: 67
Views: 79103
Reputation: 131978
Yes, because std::vector
is a value-type rather than a reference type.
To put it more simply: An std::vector
considers the values in its buffer as part of itself, so that changing them means changing the vector. This may be confusing if we only think of a vector as holding a pointer to an allocated buffer and the size: We don't change these two fields when we change elements in the buffer.
It's the opposite than for pointers, which are reference-types; if you change the pointed-to value you haven't changed the pointer itself.
The fact that std::vector
is a value-type is a design choice - it is not something inherent in the C++ language. Thus, for example, the std::span
class is also basically a pair of a pointer and a size, but an std::span
can be const
while you can still change the pointed-to elements. (There are other differences between spans and vectors.)
Upvotes: 14
Reputation: 15568
Yes, a const vector
provides access to its elements as if they were const
, that is, it only gives you const
references. In your second function, it's not the objects of type A
that are const
, but pointers to them. A pointer being const
does not mean that the object the pointer is pointing to is const
. To declare a pointer-to-const, use the type A const *
.
Upvotes: 43
Reputation: 81996
So a const object can only call const methods. That is:
class V {
public:
void foo() { ... } // Can't be called
void bar() const { ... } // Can be called
};
So let's look at a vector's operator[]:
reference operator[]( size_type pos );
const_reference operator[]( size_type pos ) const;
So when the vector object is const, it will return a const_reference
.
(*v[0]).set(1234);
Let's break this down:
A * const & ptr = v[0];
A & val = *ptr;
val.set(1234);
Note that you have a constant pointer to variable data. So you can't change what is pointed at, but you can change the value that the pointer points at.
Upvotes: 22
Reputation: 726809
The first version
v[0].set (1234);
does not compile because it tries to change the vector's first element returned to it by reference. The compiler thinks it's a change because set(int)
is not marked const
.
The second version, on the other hand, only reads from the vector
(*v[0]).set(1234);
and calls set
on the result of the dereference of a constant reference to a pointer that it gets back.
When you call v[0]
on a const
vector, you get back a const
reference to A
. When element type is a pointer, calling set
on it is OK. You could change the second example to
v[0]->set(1234);
and get the same result as before. This is because you get a reference to a pointer that is constant, but the item pointed to by that pointer is not constant.
Upvotes: 24