通过智能指针分配给成员

时间:2018-03-23 14:07:44

标签: c++ pointers smart-pointers unique-ptr dereference

我对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

显然,name的{​​{1}}成员未被更改。当单步执行调试工具时,我发现智能指针指向的地址和成员的实际地址甚至不一样。但是,如果我直接获取指向同一成员的指针并尝试更改它的值,则可以正常工作:

mary

产生

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

当智能指针用于指向班级成员时,是否存在某些规范或限制?感谢。

3 个答案:

答案 0 :(得分:3)

当你这样做时

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

您没有返回指向name的指针您创建了一个std::unique_ptr<std::string>,其中包含std::string name的副本name。它与unique_ptr完全分开。

您可以创建一个具有空删除器的name,并使用指向name的指针构建它,但是当您只需通过引用返回Student(int studentID, string gender, string name) : studentID(studentID), gender(std::move(gender)), name(std::move(name)) {} 时就可以完成很多工作掌握它。

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

@RequestMapping("value = "/yourPostEndpoint", method = RequestMethod.POST)
public void postThis(HttpServletRequest request) {
    String url = request.getRequestURL().toString();
    String relativeGETUrl = url+"/yourGetEndpoint"; 
    String getEndpointResponse = new RestTemplate().getForObject(relativeGETUrl, String.class);

    // Do whatever you want to do with the get response

}

答案 1 :(得分:1)

当您使用智能指针时,每次都会创建一个值为name的智能指针的新实例,因此您的指针实际上永远不会引用成员变量{{1的内存地址但是你创建的副本。在更多带注释的术语中:

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成员变量中观察到该更改。

答案 2 :(得分:1)

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

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

相当于:

std::unique_ptr<string> p;

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

return p;