Сам, содержащий shared_ptr самого себя, унаследованный от std::enable_shared_from_this

Этот вопрос является дополнительным вопросом к этому вопросу здесь: -ptr-or-a-shared-ptr">исходный вопрос

У меня есть класс, который наследуется от std::enable_shared_from_this, и этот класс содержит std::shared_ptr<Self>

В любом из конструкторов этого класса после того, как я узнаю, что детали класса завершены и успешны, как мне присвоить сохраненному std::shared_ptr<Self> значение shared this?

Пример:

class Self : public std::enable_shared_from_this<Self> {
private:
    std::shared_ptr<Self> me_; // Or
    std::unique_ptr>Self> me_;

public:
    Self ( /*some parameters*/ );
};

Self::Self( /* some parameters */ ) {
    // Check parameters for creation

    // Some work or initialization being done

    // If all is successful and construction of this class is about
    // to leave scope, then set the smart pointer to the this*

    // How to do ...
    me_ = std::enable_shared_from_this<Self>::shared_from_this();
    // Properly if this is even possible at all.
}

person Francis Cugler    schedule 16.01.2017    source источник
comment
@ Джейсон Р, тогда ладно. Таким образом, тогда мне потребуется класс типа менеджера, который содержит их экземпляры, или мне нужно будет установить его в функции, которая будет вызываться сразу после его конструктора, такого как конструкция или функция инициализации.   -  person Francis Cugler    schedule 16.01.2017
comment
Shared_ptr для себя — это оксюморон. полезен только для временного поддержания объекта в рабочем состоянии (например, при ожидании обратного вызова).   -  person Richard Hodges    schedule 17.01.2017


Ответы (2)


Вы не можете. В этот момент shared_ptr, указывающий на текущий экземпляр Self, еще не существует. Он не может существовать до тех пор, пока не вернется конструктор. shared_from_this() имеет предварительное условие, что shared_ptr уже существует, указывающее на this.

person Jason R    schedule 16.01.2017
comment
Хорошо, это имеет смысл. Поэтому мне нужен либо класс менеджера, который содержит общие указатели, либо метод внутри этого класса, который нужно вызывать после конструктора, например метод create() или init(). - person Francis Cugler; 16.01.2017
comment
Да, наследование от этой части библиотеки для меня в новинку. - person Francis Cugler; 16.01.2017
comment
Итак, теперь вопрос только в том, по какому пути пойти... и если я выберу класс типа менеджера, тогда не должно быть необходимости наследовать этот класс от shared_from_this. - person Francis Cugler; 16.01.2017
comment
Несколько более абстрактный взгляд на это заключается в том, что объект не имеет права голоса в отношении владения самим собой — он не может принять решение о совместном использовании. - person molbdnilo; 16.01.2017
comment
@JasonR Он не может существовать до тех пор, пока не вернется конструктор. С технической точки зрения, вы не можете создать такой указатель из ctor, используя std::shared_ptr<T>(this). Это может быть плохой, плохой и опасной практикой, я просто хотел сказать, что это выглядит возможным. - person AlexD; 20.01.2017
comment
@molbdnilo Просто ради абстрактного обсуждения. Представьте, что все указатели — это умные указатели (грубо говоря, как в языках со встроенным сборщиком мусора). Тогда не будет проблем с самоуказанием. Так что я бы не сказал, что это концептуальная проблема :). - person AlexD; 20.01.2017
comment
@AlexD, да, вы можете злоупотреблять API таким образом. Но тогда вам нужно быть осторожным, чтобы либо убедиться, что shared_ptr не выходит за пределы области действия, либо предоставить для него настраиваемое средство удаления. В противном случае в конце конструктора умный указатель выйдет за пределы области видимости и удалит только что созданный объект. - person Jason R; 20.01.2017
comment
@JasonR Конечно, я понимаю, что это сомнительная практика, просто попытался сказать, что это не может существовать, слишком ограничительно :). - person AlexD; 20.01.2017

Вы не можете, потому что вы должны быть существующим std::shared_ptr, указывающим на текущий объект. Как говорит Скотт Мейерс в книге «Эффективный современный C++» (глава 19), вы можете объявить свои конструкторы закрытыми и сделать фабричную функцию, возвращающую std::shared_ptr, например:

class Self: public std::enable_shared_from_this<Self> {
public:
// factory function that perfect-forwards args
// to a private ctor
    template<typename... Ts>
    static std::shared_ptr<Self> create(Ts&&... params);
    ...
    void process();
    ...
private:
    ... // ctors
};

А затем вызовите process, это может быть что-то вроде:

void Self::process() 
{
    ... 
    me_ = shared_from_this();
}
person hlscalon    schedule 16.01.2017
comment
Я думаю, что это технически возможно (хотя может быть плохой дизайн). См. мой комментарий к ответу JasonR. - person AlexD; 20.01.2017