Хранить слабый указатель на себя

Я работаю с базой кода, которая была частично реализована кем-то, кто был влюблен в слишком сложные решения простых проблем (например, шаблоны классов с двумя параметрами, которые когда-либо создавались только для одной пары типов). Одна вещь, которую она сделала, состояла в том, чтобы создать объекты в умном указателе, и затем заставить объект хранить слабый указатель на себя.

class MyClass {
    //...
    boost::weak_ptr<MyClass> m_self;
    //...
};

boost::shared_ptr<MyClass>
Factory::Factory::Factory::CreateMyClass() {
    boost::shared_ptr<MyClass> obj(new MyClass(...));
    boost::weak_ptr<MyClass> p(obj);
    obj->storeSelfPointer(p);
    return obj;
}

Затем класс переходит к использованию m_self, блокируя его и передавая полученный общий указатель.

Что касается меня, я не могу понять, чего она пыталась достичь. Есть ли какая-то модель или идея, которая объясняет эту реализацию? Мне кажется, что это совершенно бессмысленно, и я хотел бы отменить его.

РЕДАКТИРОВАТЬ: я должен отметить, что ни одно из мест, которые используют результирующий умный указатель, полученный из блокировки m_self, на самом деле не сохраняет умный указатель.

1 ответ

Решение

Возможное использование этого "дизайна" может заключаться в использовании m_self.lock() генерировать общие указатели из этого.

Если вы удалите этот элемент слабого указателя, счетчик ссылок будет удерживаться сгенерированным общим указателем из this было бы неправильно.

Это достигает того же, чем std::enable_shared_from_this Интересно, что cppreference.com упоминает этот дизайн:

Обычная реализация для enable_shared_from_this состоит в том, чтобы содержать слабую ссылку (такую ​​как std::weak_ptr) на это. Конструкторы std::shared_ptr обнаруживают наличие базы enable_shared_from_this и назначают вновь созданный std::shared_ptr внутренне сохраненной слабой ссылке

И стандарт C++, раздел § 20.8.2.4 10, упоминает такую ​​же возможную реализацию:

Конструкторы shared_ptr, которые создают уникальные указатели, могут обнаружить присутствие enable_shared_- from_this base и назначить вновь созданный shared_ptr его члену __weak_this


Возможный рефакторинг:

  • Если вы используете C++11, вы можете удалить std::weak_ptr член, и публично наследует от std::enable_shared_from_this<T>, Вы должны получить общий указатель из этого, вызвав shared_from_this(),

  • Если вы не используете C++11, но можете использовать boost, используйте boost::enable_shared_from_this см. документацию по бусту. Вы должны получить общий указатель из этого, вызвав shared_from_this(),

  • Если вы не используете C++ 11 и не можете использовать boost, вы можете перенести предлагаемую реализацию стандарта в вашу кодовую базу, она достаточно коротка:

Код: (скопировано из § 20.8.2.4 - 11, удалите первые подчеркивания, и вы, вероятно, захотите переименовать его)

template<class T> class enable_shared_from_this {
    private:
     weak_ptr<T> __weak_this;
    protected:
     constexpr enable_shared_from_this() : __weak_this() { }
     enable_shared_from_this(enable_shared_from_this const &) { }
     enable_shared_from_this& operator=(enable_shared_from_this const &) { return *this; }
     ~enable_shared_from_this() { }
    public:
     shared_ptr<T> shared_from_this() { return shared_ptr<T>(__weak_this); }
     shared_ptr<T const> shared_from_this() const { return shared_ptr<T const>(__weak_this); }
};

И использовать shared_from_this() сделать общий указатель. Если вы скопируете этот код, обратите внимание, что построение общих указателей из этого другими способами не будет работать. Конструкторы общих указателей должны быть изменены (как объяснено в стандартной цитате выше).

Другие вопросы по тегам