Мой вопрос касается реализации шаблона оператора присваивания shared_ptr
в GCC 4.7.2, который, как я подозреваю, содержит ошибку.
ПРИМЕЧАНИЕ 1: СТАНДАРТ C++11
Вот подпись шаблона оператора присваивания, о котором я говорю:
template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
Из стандарта С++ 11 (20.7.2.2.3):
"Эквивалентно shared_ptr(r).swap(*this)
."
Другими словами, шаблон оператора присваивания определяется в терминах шаблона конструктора. Сигнатура шаблона конструктора выглядит следующим образом:
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
Из стандарта С++ 11 (20.7.2.2.1):
"Требуется: конструктор [...] не должен участвовать в разрешении перегрузки, если Y* не может быть неявно преобразован в T*."
ПРИМЕЧАНИЕ 2: РЕАЛИЗАЦИЯ GCC 4.7.2:
Теперь реализация шаблона конструктора GCC 4.7.2 кажется мне правильной (std::__shared_ptr
является базовым классом std::shared_ptr
):
template<typename _Tp1, typename =
typename std::enable_if<std::is_convertible<_Tp1*, _Tp*>::value>::type>
__shared_ptr(__shared_ptr<_Tp1, _Lp>&& __r) noexcept
:
_M_ptr(__r._M_ptr),
_M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = 0;
}
Однако реализация шаблона оператора присваивания в GCC 4.7.2 выглядит следующим образом:
template<typename _Tp1>
__shared_ptr& operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{
_M_ptr = __r._M_ptr;
_M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
return *this;
}
Что меня поражает, так это то, что эта операция не определена в терминах шаблона конструктора или swap()
. В частности, простое присвоение _M_ptr = __r._M_ptr
не дает того же результата, что и явная проверка типов _Tp1*
и _Tp*
на конвертируемость через std::is_convertible
(которые могут быть специализированы).
ПРИМЕЧАНИЕ 3: РЕАЛИЗАЦИЯ VC10
Я заметил, что VC10 имеет более подходящую реализацию в этом отношении, которую я считаю правильной и ведет себя так, как я ожидал в моих тестовых примерах (в то время как GCC этого не делает):
template<class _Ty2>
_Myt& operator=(const shared_ptr<_Ty2>& _Right)
{
// assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
ВОПРОС:
Действительно ли есть ошибка в реализации GCC 4.7.2 shared_ptr
? Я не смог найти ни одного отчета об ошибке для этой проблемы.
ПОСТСКРИПТУМ:
Если вы хотите спросить меня, каковы мои тестовые примеры, почему меня волнует эта, казалось бы, незначительная деталь и почему я, кажется, подразумеваю, что мне нужно специализироваться std::is_convertible
, пожалуйста, сделайте это в чате. Это длинная история, и невозможно подвести итог, чтобы не быть понятым неправильно (со всеми вытекающими отсюда неприятными последствиями). Заранее спасибо.
shared_ptr
- person Jonathan Wakely   schedule 08.01.2013is_convertible
, вы не должны этого делать, если не поддерживаете поведение, требуемое стандартом... - person Kerrek SB   schedule 08.01.2013std::is_convertible
, делает ли это реализацию GCC соответствующей? - person Andy Prowl   schedule 08.01.2013std::is_convertible
допустима, я не думаю, что это изменит значение фразыY*
, которая неявно преобразуется вT*
. - person aschepler   schedule 08.01.2013is_convertible
требования. Обратите внимание, что стандарт не требуетstd::is_convertible<T,U>::value
, а требует, чтобы они были конвертируемыми, и это неявно проверяется в назначении. Предоставление специализацийis_convertible
может только ограничить использование, поскольку инициализация/назначение по-прежнему должны выполняться в тех случаях, когда тест проходит. Также обратите внимание, что стандарт не требует использования SFINAE или использованияstd::is_convertible
, поэтому в зависимости от этого поведения ваша программа становится непереносимой. - person David Rodríguez - dribeas   schedule 08.01.2013std::is_convertible
нехорошо. На самом деле существует, если не указано иное, что заставляет меня задаться вопросом, есть ли случаи, когда это возможно. - person Andy Prowl   schedule 08.01.2013std::is_convertible
, аoperator =
реализован по-другому, я хотел бы выяснить, эквивалентны ли эти две реализации. - person Andy Prowl   schedule 08.01.2013operator=
было таким же, как и для конструктор+своп в стандарте. - person David Rodríguez - dribeas   schedule 08.01.2013