Один и тот же адрес, несколько shared_ptrs, enable_shared_from_this и настраиваемое средство удаления

Связано с Тот же адрес, несколько счетчиков shared_ptr , запрещено ли это стандартом C++? и множество других вопросов, связанных с несколькими объектами shared_ptr, указывающими на один и тот же объект, но не использующими общую структуру счетчика ссылок.

Что произойдет, если объект наследуется от «enable_shared_from_this» в вышеупомянутом вопросе? Что возвращает мой shared_from_this()? Один с пользовательским удалением или без?

struct B : boost::enable_shared_from_this<B> {
  boost::weak_ptr < B > get_weak() {
    return shared_from_this();
  }
};

void doNothing(B *) {
}

int main() {
  B * b0 = new B;

  boost::shared_ptr < B > sddb0(b0, doNothing);
  boost::weak_ptr < B > swddb0(sddb0->get_weak());
  //  Does this have a custom deleter???
  boost::shared_ptr < B > sddb1 = swddb0.lock();

  boost::shared_ptr < B > scdb0(b0);
  boost::weak_ptr < B > swcdb0(sddb0->get_weak());
  //  Does this *not* have a custom deleter???
  boost::shared_ptr < B > scdb1 = swcdb0.lock();
}

person zrb    schedule 09.07.2012    source источник


Ответы (1)


Средство удаления связано с принадлежащим объектом и будет использоваться для его удаления, когда последний владелец удаляет его ссылку, поэтому все указатели, которые совместно владеют одним и тем же объектом, также используют средство удаления. Средство удаления не хранится в отдельных объектах shared_ptr, оно хранится в куче вместе со счетчиками ссылок, поэтому используется всеми объектами, имеющими одни и те же счетчики.

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

Не пишите это:

B * b0 = new B;

boost::shared_ptr < B > sddb0(b0, doNothing);

Правильный способ сделать это:

boost::shared_ptr < B > sddb0(new B, doNothing);

База enable_shared_from_this<B> имеет член weak_ptr<B>, который назначается конструктором shared_ptr, так что weak_ptr разделяет владение с sddb0, как и общий указатель, возвращаемый shared_from_this().

Итак, ответ на этот вопрос — да:

//  Does this have a custom deleter???
boost::shared_ptr < B > sddb1 = swddb0.lock();

sddb1 разделяет право собственности с sddb0, поэтому у него один и тот же инструмент для удаления.

Вы можете проверить это, используя get_deleter, или записав stdout в doNothing, или используя owner_less для сравнения владельцев указателей.

Это создает объект, который не разделяет владение с существующими общими указателями:

boost::shared_ptr ‹ B > scdb0(b0);

Член weak_ptr<B> базы enable_shared_from_this<B> переназначается строкой выше, поэтому он разделяет владение с scdb0 вместо sddb0. Поэтому, когда вы вызываете get_weak после этого момента, он возвращает слабый указатель, который разделяет владение с scdb0 и поэтому не имеет специального удаления. Опять же, вы можете легко убедиться в этом, увидев, что doNothing не вызывается, или используя owner_less.

person Jonathan Wakely    schedule 28.07.2012
comment
Спасибо, что нашли время ответить на этот вопрос. Я прошел код повышения для enable_shared_from_this, и он переназначает слабый указатель, но я предполагаю, что мы должны рассматривать это как деталь реализации и не полагаться на него. - person zrb; 31.08.2012