Когда enable_shared_from_this <S>полезно? - PullRequest
2 голосов
/ 13 июня 2019

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

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

struct S
{
  shared_ptr<S> dangerous()
  {
     return shared_ptr<S>(this);   // don't do this!
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->dangerous();
   return 0;
}

Мой вопрос, почему пользователь не сделал этого

 shared_ptr<S> sp2 = sp1;

Разве это не увеличит количество ссылок? и будет хорошо? Этот пример приведен в случае, если по какой-то причине класс не имеет доступа к sp1 и должен вернуть обратно shared_ptr?

1 Ответ

2 голосов
/ 13 июня 2019

Основная проблема здесь в том, что не каждый общий указатель в вашей кодовой базе по какой-то причине «известен» остальной части кода.

Если у вас есть доступ к уже заданному shared_ptrвы всегда должны использовать shared_ptr<S> sp2 = sp1; как вы написали.Это абсолютно нормально и лучше, если использовать std::enable_shared_from_this.

. Давайте рассмотрим следующий пример:

struct S: std::enable_shared_from_this<S>
{   
    std::shared_ptr<S> getPtr() { return shared_from_this(); }
};  

// Here we have no interface for providing a shared_ptr, maybe
// code that we can't change or maintain or comes as callback from
// a library we want to use
void f( S* s ) 
{   
    // here we have no access to shared_ptr<S>...
    // so we need to have access to the unique counting instance
    // of all other shared_ptr which are pointing to this object
    std::shared_ptr<S> p3 = s->getPtr();
    std::cout << p3.use_count() << std::endl;

    // do some stuff....

}

int main()
{
    std::shared_ptr<S> p1 = std::make_shared<S>();
    std::cout << p1.use_count() << std::endl;

    // This example is useless, as you can directly use p1
    std::shared_ptr<S> p2 = p1->getPtr();
    std::cout << p1.use_count() << std::endl;
    std::cout << p2.use_count() << std::endl;

    // But if we have to use a interface, which is not providing access via shared_ptr like this:
    f(p1.get());
}  

Ключевая проблема, которая решается здесь, - просто получить доступ к общей ручке."который соединяет все остальные shared_ptr в нашей системе IF!у нас вообще нет доступа к любому из shared_ptr!

Причины, по которым мы не можем получить доступ ни к одному из существующих shared_ptr к нашему объекту, могут быть такими, как: Использование старых интерфейсов, которые допускают только необработанные указателино мы хотим использовать общий ptr в остальной части нашего кода, используя обратные вызовы из библиотек, которые также поддерживают только необработанные указатели и т. д.

Использование std::enable_shared_from_this<S> имеет некоторые недостатки:

Вашинтерфейсы больше не могут использовать const S*, так как создание нового shared_ptr изменит данные std::enable_shared_from_this, который теперь является базовым классом вашего класса или структуры.Также это увеличивает размер вашего объекта.

...