Find a Workaround
Let’s learn about some other uses of const.
We'll cover the following
Assignment Operator
Let’s implement the assignment operator! It will compile, but what should it do?
What should the assignment operator do?
MyClassWithConstMember& operator=(const MyClassWithConstMember&) {
// ???
return *this;
}
Interestingly, the assignment operator allows us to get around a const
variable’s assignment restriction.
const_cast
We can try to use const_cast
to change a const
variable.
#include <utility>#include <iostream>class MyClassWithConstMember {public:MyClassWithConstMember(int a) : m_a(a) {}MyClassWithConstMember& operator=(const MyClassWithConstMember& other) {int* tmp = const_cast<int*>(&m_a);*tmp = other.m_a;std::cout << "copy assignment \n";return *this;}int getA() {return m_a;}private:const int m_a;};int main() {MyClassWithConstMember o1{666};MyClassWithConstMember o2{42};std::cout << "o1.a: " << o1.getA() << std::endl;std::cout << "o2.a: " << o2.getA() << std::endl;o1 = o2;std::cout << "o1.a: " << o1.getA() << std::endl;}
We can cast constness away from pointers, references, or from pointers to data members, but not from values. In order to do that, we have to take the member’s address and cast it into a temporary non-const
pointer (line 10).
Is this worth it?
We have our const
member now. Our assignment is working fine. But then, if somebody wants to do similar things outside the special functions, that would be considered as a red flag in a code review.
Let’s not commit this code so fast. Using const_cast
in special functions is already a red flag because it might lead to undefined behavior!
Note: “Depending on the type of the object, a write operation through the pointer, lvalue, or a pointer to data member resulting from a
const_cast
that casts away aconst
-qualifier may produce undefined behavior.”
We’ve just looked at the copy assignment, and we know it won’t work without risking undefined behavior.
Will move semantics work when we have const
members?
We saw that the copy assignment doesn’t work, but the copy constructor would work because, in that case, values that are already initialized do not change. For move semantics, both methods do not work. It makes sense because usually the source data also changes during a move operation.
To demonstrate this, let’s change the line o1 = o2;
to o1 = std::move(o2);