Вопрос по c++, boost, c++11, copy-constructor, rvalue-reference – Почему определенный пользователем конструктор перемещения отключает неявный конструктор копирования?

33

Пока я читал boost / shared_ptr.hpp, я увидел этот код:

//  generated copy constructor, destructor are fine...

#if defined( BOOST_HAS_RVALUE_REFS )

// ... except in C++0x, move disables the implicit copy

shared_ptr( shared_ptr const & r ): px( r.px ), pn( r.pn ) // never throws
{
}

#endif

Что делает комментарий «Сгенерированный конструктор копирования, деструктор в порядке, за исключением C ++ 11, перемещение отключает неявное копирование» значит здесь? Должны ли мы всегда писать копию ctor для предотвращения этой ситуации в C ++ 11?

Ваш Ответ

2   ответа
89

потому что нашел его и точным, и юмористическим. :-)

Я даю альтернативный ответ, потому что я предполагаю из-за названия вопроса, который ОП может захотеть узнатьwhy стандарт так говорит.

background

C ++ неявно сгенерировал членов-копий, потому что, если бы он этого не сделал, он был бы по-прежнему рожден в 1985 году, потому что это былоso несовместим с C. И в этом случае мы не будем вести этот разговор сегодня, потому что C ++ не будет существовать.

Это, как говорится, неявно сгенерированные члены копии сродни "иметь дело с дьяволом". C ++ не мог родиться без них. Но они злы в том, что они молча генерируют неправильный код в значительном количестве случаев. Комитет по С ++ не глуп, они это знают.

C++11

Теперь, когда C ++ появился на свет и превратился в успешного взрослого, комитет просто хотел бы сказать: мы больше не создаем неявно генерируемые члены-копии. Они слишком опасны. Если вам нужен неявно сгенерированный участник копии, вы должны согласиться на это решение (в отличие от отказа от него). Однако, учитывая количество существующего кода C ++, который сломался бы, если бы это было сделано, это было бы равносильно самоубийству. Eстьhuge проблема обратной совместимости вполне оправдана.

Таким образом, комитет достиг компромиссной позиции: если вы объявляете перемещаемые элементы (что не может делать устаревший код C ++), то мы будем предполагать, что члены-копии по умолчанию, скорее всего, поступят неправильно. Согласие (с=default) если вы хотите их. Или пиши их сам. В противном случае они неявно удаляются. Наш современный опыт в мире с типами «только для перемещения» показывает, что эта позиция по умолчанию на самом деле довольно часто является желаемой (например,unique_ptr, ofstream, future, так далее.). И затраты на участие на самом деле довольно мало с= default.

Looking Forward

Комитет хотел бы даже сказать: если вы написали деструктор, вполне вероятно, что неявные члены копии неверны, поэтому мы удалим их. Это C ++ 98/03 "правило трех". Однако даже это сломало бы много кода. Однако комитет сказал в C ++ 11, что если вы предоставите деструктор, объявленный пользователем, неявное создание членов копииis deprecated, Это означает, что эта функция может быть удалена в будущем стандарте. И что в любой день ваш компилятор может начать выдавать «устаревшие предупреждения» в этой ситуации (стандарт не может указывать предупреждения).

Conclusion

Так что будьте предупреждены: C ++ вырос и вырос за десятилетия. И это означает, что C ++ вашего отца может нуждаться в миграции, чтобы иметь дело с C ++ вашего ребенка. Это медленный, постепенный процесс, так что вы не поднимаете руки и просто портируете на другой язык. Но этоis изменить, даже если медленно.

+1, потому что я мог только догадываться, почему. ; -]
& quot; в любой день ваш компилятор может начать выпускать & quot; устаревшие предупреждения & quot; в этой ситуации & quot; звучит как еще одно хорошее дополнение для -Wdeprecated. И предупреждение об использовании _dynamic-exception -ification_s также.
Отличное объяснениеwhy часть вопроса.
+1. Потрясающее объяснение. Довольно разумное решение, принятое комитетом.
22

& # XA7; 12,8 / 7:

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted. The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition

struct X {
    X(const X&, int);
};

a copy constructor is implicitly-declared. If the user-declared constructor is later defined as

X::X(const X& x, int i =0) { /* ... */ }

then any use of X’s copy constructor is ill-formed because of the ambiguity; no diagnostic is required.

(Акцент мой.)

@Nawaz: одинcan быть выдан, но неrequired быть выпущенным, так как это только устарело в этот момент.
no diagnostic is required.? Что это значит? Нет ошибки / предупреждение будет выдано за двусмысленность?

Похожие вопросы