Хранить слабый указатель на себя
Я работаю с базой кода, которая была частично реализована кем-то, кто был влюблен в слишком сложные решения простых проблем (например, шаблоны классов с двумя параметрами, которые когда-либо создавались только для одной пары типов). Одна вещь, которую она сделала, состояла в том, чтобы создать объекты в умном указателе, и затем заставить объект хранить слабый указатель на себя.
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()
сделать общий указатель. Если вы скопируете этот код, обратите внимание, что построение общих указателей из этого другими способами не будет работать. Конструкторы общих указателей должны быть изменены (как объяснено в стандартной цитате выше).