通过智能指针分配给类成员
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
显然,mary
的 name
成员没有改变。在逐步调试工具时,我发现智能指针指向的地址和成员的实际地址甚至都不一样。但是,如果我直接获取指向同一个成员的指针并尝试更改它的值,它会起作用:
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<std::string>
,它拥有自己的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_ptrauto student = make_unique<Student>(mary)
,并在Student
类中显式设置复制构造函数,当分配此变量时,复制构造函数被调用?那个 unique_ptr 实际上拥有自己的实例?make_unique
的任何内容都用于构造make_unique
正在制作的任何类型。例如int foo; auto bar = make_unique<int>(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;
【讨论】:
以上是关于通过智能指针分配给类成员的主要内容,如果未能解决你的问题,请参考以下文章