Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::vector of objects and const-correctness

Consider the following:

class A {
public:
    const int c; // must not be modified!

    A(int _c)
    :   c(_c)
    {
        // Nothing here
    }

    A(const A& copy)
    : c(copy.c)
    {
        // Nothing here
    }    
};



int main(int argc, char *argv[])
{
    A foo(1337);

    vector<A> vec;
    vec.push_back(foo); // <-- compile error!
    
    return 0;
}

Obviously, the copy constructor is not enough. What am I missing?

EDIT:
Ofc. I cannot change this->c in operator=() method, so I don't see how operator=() would be used (although required by std::vector).

like image 945
eisbaw Avatar asked Nov 08 '10 13:11

eisbaw


People also ask

What is const correctness in C++?

By Alex Allain. The const keyword allows you to specify whether or not a variable is modifiable. You can use const to prevent modifications to variables and const pointers and const references prevent changing the data pointed to (or referenced).

Can you add to a const vector?

You can't put items into a const vector, the vectors state is the items it holds, and adding items to the vector modifies that state. If you want to append to a vector you must take in a non const ref. Show activity on this post. If you have a const vector it means you can only read the elements from that vector.

Can a const vector be modified?

If the vector itself is declared const (as in const std::vector<T*>), then you can't modify the vector, but you can modify the objects. If the pointers are declared const (as in std::vector<const T*>), then you can modify the vector, but not the objects.

What does const vector mean?

A const vector will return a const reference to its elements via the [] operator . In the first case, you cannot change the value of a const int&. In the second case, you cannot change the value of a reference to a constant pointer, but you can change the value the pointer is pointed to.


2 Answers

I'm not sure why nobody said it, but the correct answer is to drop the const, or store A*'s in the vector (using the appropriate smart pointer).

You can give your class terrible semantics by having "copy" invoke UB or doing nothing (and therefore not being a copy), but why all this trouble dancing around UB and bad code? What do you get by making that const? (Hint: Nothing.) Your problem is conceptual: If a class has a const member, the class is const. Objects that are const, fundamentally, cannot be assigned.

Just make it a non-const private, and expose its value immutably. To users, this is equivalent, const-wise. It allows the implicitly generated functions to work just fine.

like image 183
GManNickG Avatar answered Sep 27 '22 20:09

GManNickG


An STL container element must be copy-constructible and assignable1(which your class A isn't). You need to overload operator =.

1 : §23.1 says The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignabletypes


EDIT :

Disclaimer: I am not sure whether the following piece of code is 100% safe. If it invokes UB or something please let me know.

A& operator=(const A& assign)
{
    *const_cast<int*> (&c)= assign.c;
    return *this;
}

EDIT 2

I think the above code snippet invokes Undefined Behaviour because trying to cast away the const-ness of a const qualified variable invokes UB.

like image 39
Prasoon Saurav Avatar answered Sep 27 '22 18:09

Prasoon Saurav