Гарантируется ли, что weak_ptr истечет, когда shared_ptr будет сброшен на тот же адрес, который содержит?

Гарантируется ли, что weak_ptr истечет, когда shared_ptr будет сброшен на тот же адрес, который содержит?

#include <cassert>
#include <memory>

int main()
{
    int* i = new int(0);
    std::shared_ptr<int> si( i );
    std::weak_ptr<int> wi = si;

    si.reset( i );

    assert( wi.expired() ); // wi.expired() == true (GCC 4.7)
}

Или это тот случай, когда значение wi.expired() не определено?

ИЗМЕНИТЬ:

Теперь я немного изменяю вопрос:

Гарантируется ли, что срок действия weak_ptr истечет, когда shared_ptr будет сброшен на тот же адрес, который содержал shared_ptr при инициализации weak_ptr?

#include <cassert>
#include <memory>

int main()
{
    int* i = new int(0);
    std::shared_ptr<int> si( i );
    std::weak_ptr<int> wi = si;

    si.reset();

    int* j = new int(0); 
    // Suppose that new returns the same address that contains variable i :  
    assert(j == i); 

    si.reset( j );

    assert( wi.expired() ); // wi.expired() == true (GCC 4.7)
}

person user3123061    schedule 17.07.2014    source источник
comment
Связанный с этим вопрос: Что произойдет, если я сброшу std:: shared_ptr самому себе.   -  person ComicSansMS    schedule 17.07.2014


Ответы (1)


С одной стороны, так и должно быть. С другой стороны, неправильно назначать один и тот же указатель двум разным общим указателям (si-before-reset и si-after-reset). На самом деле при вызове si.reset(i) бывает, что:

  • счетчик ссылок si падает до 0
  • delete i вызывается
  • возрожденный si снова указывает на i.

поэтому вновь назначенный i после сброса будет указывать на невыделенную память, а wi правильно истек (и приведет к segfault, когда si исчезнет, ​​в конце концов, пытаясь снова удалить i).

Хорошей практикой является никогда не ссылаться на голый указатель после того, как он был назначен на shared_ptr.

ОТВЕТ ПОСЛЕ РЕДАКТИРОВАНИЯ:

То же самое и здесь: тот факт, что указатель тот же, не имеет ничего общего с shared_ptr и его внутренним счетчиком ссылок. Это может быть яснее на примере «зла». Это не верно:

  int *i = new int;

  std::shared_ptr<int> si1(i);
  std::shared_ptr<int> si2(i); // deleting twice i on destruction of si2 - boom!
  std::weak_ptr<int> wi1 = si1;

  si1.reset();
  assert (wi1.expired());      // true

это похоже (действительно то же самое) на ваш первый пример: si1 и si2 - это два разных shared_ptr (они были si-before-reset и si-after-reset). Тот факт, что si1 и si2 (ошибочно) указывают на одну и ту же память, не имеет ничего общего со сроком службы общих_ptr и связанных с ними weak_ptr.

Абсолютное значение указателя i не используется для определения счетчика ссылок. Как для shared_ptr, так и для weak_ptr. Так что да, это гарантировано!

На самом деле, когда вам нужен shared_ptr объекта внутри его класса, вам нужно enable_shared_from_this — если вы использовали shared_ptr(this) вместо shared_from_this(), вы каждый раз получать разные shared_ptr - уничтожать ваш объект, как только первый из них исчерпал количество ссылок.

person Sigi    schedule 17.07.2014