Find a Workaround

Let’s learn about some other uses of const.

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 a const-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);