СТД :: enable_shared_from_this; публичный против частного

Я немного поигрался с использованием shared_ptr и enable_shared_from_this, пока столкнулся с чем-то, чего я не совсем понимаю.

В моей первой попытке я построил что-то вроде этого:

class shared_test : std::enable_shared_from_this<shared_test> {
public:
void print(bool recursive) {
if (recursive) {
shared_from_this()->print(false);
}

std::cout << "printing" << std::endl;
}
};

Обратите внимание, что этот класс является частным расширением std :: enable_shared_from_this. Это очевидно имеет большое значение, потому что выполнение чего-то вроде этого:

int main() {
auto t(std::make_shared<shared_test>());
t->print(true);
return 0;
}

выдает исключение bad_weak_ptr. Где, как будто я изменяю определение класса на публично присущий с std :: enable_shared_from_this, это работает просто найти.

Почему это, что я здесь скучаю? И нет ли способа заставить его работать для частного наследования, поскольку «внешний мир» класса shared_test не должен знать, что он разрешает общий доступ из этого … (по крайней мере, если вы не спросите меня, или я что то снова пропускаю?)

13

Решение

Почему это, что я здесь скучаю?

Делать shared_from_this Работа enable_shared_from_this должен знать о shared_ptr который держит класс. В вашей реализации STL это weak_ptr, через другие реализации возможны. Когда вы наследуете конфиденциально, тогда невозможно получить доступ к свойствам базового класса извне вашего класса. На самом деле даже невозможно понять, что вы унаследовали от. Так make_shared генерирует обычную инициализацию shared_ptr без установки соответствующих полей в enable_shared_from_this,

Исключение выбрасывается не из make_shared но форма shared_from_this так как enable_shared_from_this не был правильно инициализирован.

И нет ли способа заставить его работать для частного наследования, поскольку «внешний мир» класса shared_test не должен знать, что он разрешает общий доступ из этого …

Нет. Внешний мир должен знать, что объект имеет особые отношения с shared_ptr для правильной работы с ним.

9

Другие решения

нет ли способа заставить его работать для частного наследования, так как «внешний мир» класса shared_test не должен знать, что он разрешает общий доступ из этого

shared_ptr сам является частью «внешнего мира»; shared_ptr конструктор должен иметь возможность доступа к enable_shared_from_this подобъект базового класса shared_test объект, на который он указывает, для инициализации частного weak_ptr член enable_shared_from_this реализация.

5

Основываясь на документации, необходимо публично наследовать для доступности функции-члена «shared_from_this».

«Публичное наследование от std :: enable_shared_from_this предоставляет типу T функцию-член shared_from_this» — из ссылки CPP
http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

shared_from_this:

возвращает shared_ptr, который разделяет владение * this
(функция публичного члена)

0

Я анализирую этот вопрос из кода в STL:

auto t (std :: make_shared ());

строка кода создает shared_ptr; сначала мы погрузимся в функцию make_shared

 // FUNCTION TEMPLATE make_shared
template<class _Ty,
class... _Types>
NODISCARD inline shared_ptr<_Ty> make_shared(_Types&&... _Args)
{    // make a shared_ptr
const auto _Rx = new _Ref_count_obj<_Ty>(_STD forward<_Types>(_Args)...);

shared_ptr<_Ty> _Ret;
_Ret._Set_ptr_rep_and_enable_shared(_Rx->_Getptr(), _Rx);
return (_Ret);
}

Внимание: мы погрузимся в функцию _Ret.Set_ptr_rep_and_enable_shared.И мы можем видеть следующее:

template<class _Ux>
void _Set_ptr_rep_and_enable_shared(_Ux * _Px, _Ref_count_base * _Rx)
{    // take ownership of _Px
this->_Set_ptr_rep(_Px, _Rx);
_Enable_shared_from_this(*this, _Px);
}

Итак, мы находим функцию _Enable_shared_from_this, далее:

 template<class _Other,
class _Yty>
void _Enable_shared_from_this(const shared_ptr<_Other>& _This, _Yty * _Ptr)
{   // possibly enable shared_from_this
_Enable_shared_from_this1(_This, _Ptr, _Conjunction_t<
negation<is_array<_Other>>,
negation<is_volatile<_Yty>>,
_Can_enable_shared<_Yty>>{});
}

Мы находим ключевую точку: _Can_enable_shared<_Yty>

template<class _Yty,
class = void>
struct _Can_enable_shared
: false_type
{   // detect unambiguous and accessible inheritance from enable_shared_from_this
};

template<class _Yty>
struct _Can_enable_shared<_Yty, void_t<typename _Yty::_Esft_type>>
: is_convertible<remove_cv_t<_Yty> *, typename _Yty::_Esft_type *>::type
{   // is_convertible is necessary to verify unambiguous inheritance
};

мы находим, что только _Yty имеет _Esft_type и _Yty может быть преобразовано в _Esft_type, может _Yty может быть enable_shared (Если вы хотите узнать больше, вы можете увидеть set_black_ptr в _Yty или вы можете получить ошибку bad_weak_ptr при использовании shared_from_this).
Так что же такое _Esft_type?

 template<class _Ty>
class enable_shared_from_this
{   // provide member functions that create shared_ptr to this
public:
using _Esft_type = enable_shared_from_this;
...
}

поэтому _Esft_type просто означает enable_shared_from_this<_Ty>, поэтому, если вы используете приватное наследование, снаружи не только не видно _Esft_type, но _Yt не может быть преобразовано в _Esft_type. Таким образом, weak_ptr не может быть установлен, так что bad_weak_ptr может быть вызван.

Таким образом, извне нужно знать о существовании _Esft_type, поэтому, когда создается shared_ptr, может также быть установлен слабый_портал shared_test.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector