При звонке shared_from_this
из типов, которые наследуются от enable_shared_from_this
, очень плохие вещи (ТМ) могут случиться, если this
в настоящее время не проводится shared_ptr
объект (обычно сбой приложения). Можно ли в C ++ 14 (не 17) проверить, безопасно ли это?
Редактировать: не использовать исключения или попробовать / поймать.
Это деталь реализации, но не могли бы вы сделать что-нибудь неприятное с внутренней декларацией друга:
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 является указателем const, поэтому вам нужно дополнительное косвенное обращение, чтобы потерять const, или, если вы все равно пачкаетесь, отбросьте его!] , Оберните все это в класс, из которого вы потом производите вместо 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.
Если какой-либо другой объект в вашей программе имеет доступ к необработанному объекту this
указатель, то вы используете shared_ptr
совершенно неверный путь.
Любой указатель на ваш объект для внешнего использования ДОЛЖЕН быть помещен в shared_ptr<YourObject>
значение экземпляра, без исключений.
Если this
не проводится shared_ptr
тогда ты ничего не сможешь сделать. Из контекста: Разрешается вызывать 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
В другом месте вы не можете быть уверены. После звонка 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();
}