Могу ли я проверить, безопасно ли вызывать `shared_from_this`? - PullRequest
0 голосов
/ 08 июня 2018

При вызове shared_from_this из типов, которые наследуются от enable_shared_from_this, могут произойти очень плохие вещи (TM), если this в данный момент не удерживается объектом shared_ptr (обычносбой приложения).Можно ли в C ++ 14 (не 17) проверить, безопасно ли это?

Редактировать: Не использовать исключения или try / catch.

Ответы [ 3 ]

0 голосов
/ 10 июня 2018

Если this не удерживается shared_ptr, то вы ничего не можете сделать.Из cppreference: Разрешается вызывать shared_from_this только для ранее общего объекта, то есть для объекта, управляемого std :: shared_ptr. Вот пример этого:

#include <memory>

class MyClass;

std::shared_ptr<MyClass> global;

void resetGlobal()
{
    global = std::make_shared<MyClass>();
}

class MyClass : public std::enable_shared_from_this<MyClass>
{
public:
    void use()
    {
        resetGlobal();
        shared_from_this();
    }
};

int main()
{
    global = std::make_shared<MyClass>();
    global->use();
    return 0;
}

Наначало use метода shared_from_this должно быть в порядке (за исключением многопоточной среды без мьютексов), но после вызова любой функции, которая может изменить shared_ptr s в другом месте, вы не можете быть уверены.После вызова resetGlobal функция this просто уничтожается, и любой доступ к ней является неопределенным поведением, поэтому может привести к ошибке сегментации.

Единственный способ убедиться, что весь вызов метода shared_from_this действителен, этосделать временный shared_ptr в начале звонка:

void use()
{
    std::shared_ptr<MyClass> tmp = shared_from_this();
    resetGlobal();
    shared_from_this();
}

или

{
    std::shared_ptr<MyClass> tmp = global;
    global->use();
}
0 голосов
/ 26 сентября 2018

Если какой-либо другой объект в вашей программе имеет доступ к необработанному указателю this вашего объекта, то вы используете shared_ptr совершенно неверно.

Любой указатель на ваш объект, который будет использоваться внешне для вашегообъект ДОЛЖЕН быть обернут в экземпляр значения shared_ptr<YourObject>, без исключений.

0 голосов
/ 08 июня 2018

Это деталь реализации, но не могли бы вы сделать что-то неприятное с внутренним объявлением друга:

template<typename _Tp1>
friend void
__enable_shared_from_this_helper(const __shared_count<>& __pn,
                 const enable_shared_from_this* __pe,
                 const _Tp1* __px) noexcept

Реализуйте свою собственную версию с _Tp1 как weak_ptr <> *, которая возвращает слабый указатель [На самом деле нетточно так же, как __px является указателем на константу, поэтому вам нужно дополнительное косвенное обращение, чтобы потерять констант, или, если вы все равно пачкаетесь, выбросьте его!].Оберните все это в класс, из которого вы потом производите вместо enable_shared_from_this:

#if >= C++17
using enable_shared_from_this_c17 = enable_shared_from_this;
#else

template<typename _Tp>
enable_shared_from_this_c17: public enable_shared_from_this<_Tp>
{

  weak_ptr<_Tp> weak_from_this()
  {
    weak_ptr<_Tp> rv; auto rv2 = &rv;
    __enable_shared_from_this_helper(*(const __shared_count<>*)nullptr, this, &rv2);
    return rv;
  }
}
#endif

Теперь у вас есть реализация weak_from_this () в c ++ 14.Да, это неприятный клочок, но это только до тех пор, пока вы не обновитесь до 17.

В качестве альтернативы просто поймайте исключение!

Третий вариант - добавьте экземплярную оболочку шаблона, которая устанавливает "сконструированный"в оболочке для enable_shared_from_this, который оборачивает shared_from_this (), поэтому он терпит неудачу до тех пор, пока не будет установлен созданный флаг.

enable_shared_from_this
    safe_shared_from_this
        your interfaces
            your_implementation
                constructed<your_implementation>

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

...