Modifying Reference Member from Const Member Function in C++

Modifying reference member from const member function in C++

Because you are not changing any variable in X. Actually, you are changing _y which is an outsider with respect to your class. Don't forget that:

y = newY;

Is assigning the value of newY to the variable pointed by y, but not the references them selves. Only on initialization the references are considered.

Why can reference members be modified by const member functions?

The const qualifier of a class member function indicates that this member function (e.g., foo::operator() const) cannot change the state of the object from the client's point of view (i.e., it's abstract state). This is not exactly the same as saying that the object's raw bits are not going to change.

It is forbitten to C++ compilers to consider objects as raw bits, unless they can resolve the problem of aliasing. which in your case the compiler cannot. This is due to the fact that a non-constant alias exists (i.e., std::string &str) and consequently the state of the object is modifiable.

That is, calling operator() on object a does not change the state of a (i.e., although ext has changed, the str still remains an alias of ext).

The above also explains why pointing at an object with a pointer to constant (i.e., std::string * const str) does not guarantee that the object won't be modified. It only guarantees that the object won't change through that pointer.

const member function can modify data member

The calculator class has a const member function called calculateStart() which sets (i.e. modifies) the reference returned from calling the Parms() function in the Calculator class.

Yes, calculateStart() does modify the Calculator object, which is unexpected considering the final const qualifier in its definition.

Why ? Look at definition of inline const ParmsPtr& Layout::parms() const; the final const tells the compiler that the function will not modify the Layout object, though it actually does. How ? By mischeviously const_cast'ing the object to a non-const object; that's where the constness is broken and that's why setParms() can be called.

This is a bad practice, though there may be some reasons to do it. In such cases, const_cast serves this purpose.

C++ const member functions are modifying member variables

Your member variable is not X, but pointer to X. As long as foo does not modify the pointer, it can be const.

Why is it possible to modify object state via const member function that uses pointer to the object's member?

During the construction and destruction of an object, the members are not const. That means you can store a non-const pointer to a member that is going to be const once the object is constructed. Using that pointer to change value of a const object is undefined behavior. Quoting cppreference:

Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.

And quoting [dcl.type.cv]/4:

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

Why the need for both const reference and const member function?

  1. return a const reference to prevent the function to change the returning value
  2. a const member function that cannot modify the object. in this case, it would be like this

This could have been a bit more clearer, I'll try my shot at explaining it better.

Returning a const reference prevent the returned object to be mutated by callers.

Here's an example:

// let get_name be `const std::vector<std::string>& get_name()`

np1.get_name().size(); // ok, size is a const function of vector
np1.get_name().push_back("hello"); // ERROR! push_back is not a const function of vector

So indeed, a caller cannot change the name vector. The return type is const qualified.

However, if the function get_name itself is not const qualified (not the return type), then it is allowed to change name from the class itself.

You see, member functions receive a hidden this parameter, which is a pointer to the object being called on. The pointer can either point to a const object, or a mutable object. Here's the comparison:

// returning const ref, callers cannot change the name vector
const std::vector<std::string>& get_name() {
// The function receive a `this` that points to a mutable,
// we can change the name from the inside
this->name.push_back("another");
return name;
}

// the `this` pointer points to const -----v---v
const std::vector<std::string>& get_name() const {
this->name.push_back("another"); // ERROR! Cannot mutate member of const object
return name;
}

Const-qualified member function are really useful for the caller, as it knows that whenever this function is called, its state won't change.

For example, not only you know that the vector::size() function won't mutate the vector, but the compiler guarantees it since it's a const qualified member function.

And for the last bit, the code you posted here:

vector<string> get_name() const { return name; } 

This will not return a reference, but will make a copy. The caller can mutate the copy however it wants, but cannot mutate name itself.

Here's an example of a copy mutated:

auto name_copy = np1.get_name();

name_copy.push_back("another name"); // works, we mutated the copy by adding an element

Is it possible change value of Member variable within const function?

Though this is not appreciated, but C++ provides “Backdoors” which can be used to breach its own regulations, just like dirty pointer tricks. Anyway, you can easily do this by using a casted version of “This” pointer :

class A (){
int x;
public:
void func () const {
//change value of x here
A* ptr = const_cast<A*> (this);
ptr->x= 10; //Voila ! Here you go buddy
}
}

How const member function can change an object's data?

The member function being const means that, as far as the function is concerned, the this object (the BinTree<T>) is const. (And of course val is const because it is marked such.) (Edit: It's a bit surprising, as insert doesn't sound like the sort of function you would do to a const tree, as you wouldn't be able to update any of the internal data structures.)

Your function signature is correct -- first one means "thing pointed to" is const, second one means pointer itself is const.


EDIT based on further discussion in comments:
The function considers the this object to be const, and the node to be non-const. As such, you can't change any of the member variables directly. However, if node happens to be a reference to a member of this (say it was called via

foo.insert(foo.root);

then that particular member variable can be changed, but only through the alias of node. The compiler is not going to even notice that the two objects this and node are related, because at the time that it's looking at the function insert they're not (only when the call actually happens does the aliasing occur). The const only applies to the (literal, if implied) this; any other pointers or references hanging around can do what they want.



Related Topics



Leave a reply



Submit