Search code examples
c++pointerssmart-pointersunique-ptrdereference

Assignment through smart pointer to class members


I'm still quite new to C++, and when I was exploring smart pointers, there was a behavior that I couldn't fully understand.

Consider the following simple class:

class Student {

public:
    int studentID;
    string gender;
    string name;

    Student(int studentID, string gender, string name)
    {
        this->studentID = studentID;
        this->gender = std::move(gender);
        this->name = std::move(name);
    }

    unique_ptr<string> getNameUnique()
    {
        return make_unique<string>(this->name);
    }

    string* getNamePtr()
    {
        return &name;
    }

};

In the main code, if I get the smart pointer that points to the name of an instance and try to modify it, it won't work:

auto nameUniquePtr = mary.getNameUnique();
cout << "Before: " << mary.name << "\n";
cout << "Before (through pointer): " << *nameUniquePtr << "\n";
*nameUniquePtr = "Tracy";
cout << "After: " << mary.name << "\n";
cout << "After (through pointer): " << *nameUniquePtr << "\n\n";

produces:

Before: Mary
Before (through pointer): Mary
After: Mary
After (through pointer): Tracy

Apparently, the name member of mary wasn't changed. When stepping through the debug tools, I found that the addresses the smart pointer pointed to and the actual address of the member weren't even the same. However, if I directly get the pointer to the same member and try to change the value of it, it works:

auto namePtr = mary.getNamePtr();
cout << "Before: " << mary.name << "\n";
cout << "Before (through pointer): " << *namePtr << "\n";
*namePtr = "Tracy";
cout << "After: " << mary.name << "\n";
cout << "After (through pointer): " << *namePtr << "\n\n";

produces:

Before: Mary
Before (through pointer): Mary
After: Tracy
After (through pointer): Tracy

Even if I directly set a smart pointer variable that points to the member and change the value through it, it still won't work:

auto directPtr = make_unique<string>(mary.name);
cout << "Before: " << mary.name << "\n";
*directPtr = "Jessica";
cout << "After: " << mary.name << "\n\n";

produces:

Before: Tracy
After: Tracy

Are there some specifications or limitations when smart pointers are used to point to class members? Thanks.


Solution

  • When you do

    return make_unique<string>(this->name);
    

    You are not returning a pointer to name You create a std::unique_ptr<std::string> that holds it's own std::string that is a copy of name. it is completely separate from name.

    You could create a unique_ptr that has a null deleter and construct it with a pointer to name but that is a lot of work when you could simply return name by reference to get a handle to it.


    I would also like to point out that you should use a member initialization list to initialize your class members. What you are doing is assinging in the constructor body which is not as efficent. For you that would look like

    Student(int studentID, string gender, string name) : studentID(studentID), gender(std::move(gender)), name(std::move(name)) {}