如何通过传递 "this" 关键字来分配 weak_ptr?

How do you assign weak_ptr by passing the "this" keyword?

在我的程序中,Groups 将共享指向 Subjects 的指针;并且 Subjects 将有指向其 Groups 的弱指针。我希望 Group 有一个 join() 函数,将 Subject 的弱指针分配给它自己。以下是我尝试过的最少代码。如何修复 join() 函数?

#include <iostream>
#include <string>
#include <memory>

class Party;

class Subject
{
public:
    std::weak_ptr<Party> MyParty;
};

class Party
{
public:
    std::string Name;

    void join(std::shared_ptr<Subject> subject)
    {
        subject->MyParty = std::make_shared<Party>(*this); // <---- PROBLEM
    }
};

int main()
{
    auto& BlueParty = std::make_shared<Party>();
    BlueParty->Name = "Blue Party";

    auto& Jane = std::make_shared<Subject>();

    BlueParty->join(Jane);

    if (auto ptr = Jane->MyParty.lock())
    { 
        std::cout << "I am in " << ptr->Name << std::endl; 
    }

    else { std::cout << "I have no party." << std::endl; }

    return 0;
}

程序打印出"I have no party"。如果赋值成功,应该会打印出"I am in Blue Party".

subject->MyParty = std::make_shared<Party>(*this); 创建了一个新的 Party 对象,该对象是 *this 的副本并由临时 std::shared_ptr 管理。 subject->MyParty 是从那个临时 shared_ptr 分配的,但是 weak_ptr 不会让它们指向的对象保持活动状态。一旦该语句完成,make_shared 返回的临时 shared_ptr 将被销毁并获取它正在管理的 Party 对象。 subject->MyParty 现在不指向任何东西。

解决方法是使用std::enable_shared_from_this:

class Party : public std::enable_shared_from_this<Party>
{
public:
    std::string Name;

    void join(std::shared_ptr<Subject> subject)
    {
        subject->MyParty = shared_from_this();
    }
};

Example

要使用 shared_from_this,对象 必须 属于 std::shared_ptr。在这种情况下,将 class 的构造函数标记为 private 并使用一个工厂函数 returns 一个 shared_ptr 到一个新实例通常是个好主意,这样不会意外创建不受 shared_ptr 管理的那种类型的对象:

class Party : public std::enable_shared_from_this<Party>
{
public:
    std::string Name;

    static std::shared_ptr<Party> create()
    {
        return std::shared_ptr<Party>{new Party()};
    }

    void join(std::shared_ptr<Subject> subject)
    {
        subject->MyParty = shared_from_this();
    }
private:
    Party() = default;
    Party(const Party&) = delete;
};

Example

遗憾的是,这使得 std::make_shared 更难使用。有关该问题的更多信息,请参阅 this question.