通过智能指针分配给类成员

Posted

技术标签:

【中文标题】通过智能指针分配给类成员【英文标题】:Assignment through smart pointer to class members 【发布时间】:2018-03-23 14:07:43 【问题描述】:

我对 C++ 还是很陌生,在探索智能指针时,有一个我无法完全理解的行为。

考虑以下简单类:

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;
    

;

在主代码中,如果我得到指向实例的name的智能指针并尝试修改它,它不会起作用:

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";

产生:

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

显然,maryname 成员没有改变。在逐步调试工具时,我发现智能指针指向的地址和成员的实际地址甚至都不一样。但是,如果我直接获取指向同一个成员的指针并尝试更改它的值,它会起作用:

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";

产生:

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

即使我直接设置了一个指向成员的智能指针变量并通过它改变值,还是不行:

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

产生:

Before: Tracy
After: Tracy

在使用智能指针指向类成员时是否有一些规范或限制?谢谢。

【问题讨论】:

【参考方案1】:

当你这样做时

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

您没有返回指向name 的指针,而是创建了一个std::unique_ptr&lt;std::string&gt;,它拥有自己的std::string,它是name 的副本。它与name 完全分开。

您可以创建一个具有空删除器的unique_ptr,并使用指向name 的指针构造它,但是当您可以通过引用简单地返回name 以获取它的句柄时,这是很多工作。


我还想指出,您应该使用member initialization list 来初始化您的班级成员。您正在做的是在构造函数主体中进行分配,这不是那么有效。对你来说,看起来像

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

【讨论】:

非常感谢。为什么如果我通过这样做设置一个 unique_ptr 变量:auto student = make_unique&lt;Student&gt;(mary),并在Student 类中显式设置复制构造函数,当分配此变量时,复制构造函数被调用?那个 unique_ptr 实际上拥有自己的实例? @GaryC。是的。如果您传递给make_unique 的任何内容都用于构造make_unique 正在制作的任何类型。例如int foo; auto bar = make_unique&lt;int&gt;(foo); 初始化一个新的int,它是foo 的副本【参考方案2】:

当你使用你的智能指针时,你每次都创建一个新的智能指针实例,其值为name,所以你的指针实际上并不指向成员变量name的内存地址,而是您创建的副本。用更多注释的术语:

unique_ptr<string> getNameUnique()

    return make_unique<string>(this->name); //copy the value of name into a new object that is a smart pointer

您可以考虑改用shared_ptr,如下所示:

class Student 

public:
  std::shared_ptr<std::string> name;      
  //.. other member variables

  Student(int studentID, string gender, string name)
  
    //same as before except for
    this->name = std::make_shared<std::string>(name);
  

  shared_ptr<std::string> getNameShared()
  
     return this->name;
  
  //otherwise the same
;

这会将name 的值存储在类中的智能指针中。然后可以从您的成员函数返回此 shared_ptr,并且该返回值的所有者将拥有指向您的 Student 实例所拥有的相同内存空间的指针。然后,如果您在类之外修改此智能指针的内容,您将在name 成员变量内也观察到该更改。

【讨论】:

【参考方案3】:

如果您考虑以下代码,这可能有助于您理解正在发生的事情:

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

相当于:

std::unique_ptr<string> p;

p.reset(new string(this->name));

return p;

【讨论】:

以上是关于通过智能指针分配给类成员的主要内容,如果未能解决你的问题,请参考以下文章

C++primer第十二章读书笔记---动态内存与智能指针

c++动态内存管理与智能指针

动态内存1(动态内存与智能指针)

“指向成员的智能指针”的真实示例是啥?

enote笔记法使用范例——指针智能指针

智能指针