c++member-functionsconst-reference

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


I'm doing the exercises from "Programming Principles and Practice using C++" and I found a class with this member function here:

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

where name is a vector: vector< string> name;

The book presents 2 concepts so far (up to page 235):

  1. return a const reference to prevent the function to change the returning value:

    const vector<string> &get_name() { return name; } 
    
  2. a const member function that cannot modify the object. in this case, it would be like this:

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

Maybe I'm not getting this completely, but aren't those 2 concepts the same? Not wanting to change the "name" vector.

Why the need for both "const"?

Thanks to anyone taking the time to reply!


Solution

    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