通过智能指针修改C++类成员变量失效问题咨询
嘿,这个问题其实是对getNameUnique()函数返回值的本质理解不到位,咱们来一步步理清楚:
核心原因:getNameUnique()返回的是拷贝对象的智能指针
看一下你的getNameUnique()实现:
unique_ptr<string> getNameUnique() { return make_unique<string>(this->name); }
这里的make_unique<string>(this->name)做了一件关键的事:创建一个全新的std::string对象,把this->name的内容拷贝到这个新对象里,然后返回指向这个新对象的unique_ptr。
也就是说,你拿到的nameUniquePtr指向的根本不是mary对象里的name成员,而是一个完全独立的、在堆上新建的字符串副本。所以你修改*nameUniquePtr的时候,只是修改了这个副本的值,和mary.name没有任何关系——这就是为什么调试时看到两个地址不一样,输出里原成员没变化的原因。
为什么普通指针getNamePtr()能生效?
再看getNamePtr()的实现:
string* getNamePtr() { return &name; }
这个函数直接返回了mary.name成员变量的内存地址,你拿到的指针直接指向mary对象里的那个string。所以通过这个指针修改值,就是直接操作mary.name的内存,自然会看到原对象的成员被改变。
额外提醒:不要试图返回指向类成员的unique_ptr
如果你想让智能指针能修改原成员,可能会想改成:
// 绝对不要这么做! unique_ptr<string> getNameUnique() { return unique_ptr<string>(&this->name); }
这是严重错误的!因为unique_ptr的职责是管理对象的所有权,当它被销毁时会自动调用delete释放指向的内存。但this->name是Student对象的成员,它的内存是和Student对象一起分配的(要么在栈上,要么在堆上作为Student的一部分),Student对象销毁时会自动处理这个成员的内存。如果返回指向它的unique_ptr,最后会导致双重释放的未定义行为。
如果需要通过指针修改原成员,直接用普通指针、引用,或者返回string&会更合适。
内容的提问来源于stack exchange,提问作者Gary C.

