简体   繁体   中英

const vector implies const elements?

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);
} // ()

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 * .

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.

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 .

About: (*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.

Yes, because std::vector is a value-type rather than a reference type.

To simplify things: 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's 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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM