Как назначить слабый_птр, передав ключевое слово "это"? - PullRequest
1 голос
/ 14 июня 2019

В моей программе группы будут иметь общие указатели на темы; и субъекты будут иметь слабые указатели на свои группы. Я хочу, чтобы у группы была функция join (), которая присваивает слабый указатель субъекта на себя. Ниже приведен минимальный код для того, что я пробовал. Как исправить функцию 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;
}

Программа распечатывает "У меня нет вечеринки". Если задание было выполнено успешно, оно должно было распечатать «Я в синей партии».

1 Ответ

5 голосов
/ 14 июня 2019

Строка subject->MyParty = std::make_shared<Party>(*this); создает новый Party объект, который является копией *this и управляется временным std::shared_ptr.subject->MyParty получает назначение из этого временного shared_ptr, но weak_ptr s не сохраняет объекты, на которые они указывают, живыми.Как только этот оператор завершается, временный shared_ptr, возвращаемый make_shared, уничтожается и получает объект 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();
    }
};

Пример

Чтобы использовать shared_from_this, объект должен принадлежать std::shared_ptr.Как правило, в таком случае рекомендуется пометить конструкторы класса private и использовать фабричную функцию, которая возвращает 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;
};

Пример

К сожалению, это затрудняет использование std::make_shared.Для получения дополнительной информации по этому вопросу см. этот вопрос .

...