Почему неявно и явно удаленные конструкторы перемещения обрабатываются по-разному?
Чтообоснование позади разной обработки неявно и явно удаленных конструкторов перемещения в стандарте C ++ 11, в отношении неявной генерации конструкторов перемещения, содержащих / наследующих классы?
C ++ 14 / C ++ 17 что-нибудь изменить? (КромеDR1402 в C ++ 14)
Примечание: я понимаю, что происходит, я понимаю, что это в соответствии с правилами стандарта C ++ 11, я заинтересован в обосновании этих правил, которые подразумевают такое поведение (пожалуйста, убедитесь, что вы просто не повторяете, что это так это потому что стандарт так говорит)
Принять классExplicitDelete
с явно удаленным движением ctor и явно дефолтным копированием ctor. Этот класс неmove constructible
хотясовместимый Копирование ctor доступно, потому что разрешение перегрузки выбирает конструктор перемещения и завершается неудачно во время компиляции из-за его удаления.
Принять классImplicitDelete
который содержит или наследует отExplicitDelete
и больше ничего не делает. Этот класс будет иметь свой ctor перемещения, неявно объявленный как удаленный из-заC ++ 11 перемещает ctor правила, Тем не менее, этот класс все еще будетmove constructible
через его копию ctor. (Связано ли это последнее утверждение с разрешениемDR1402?)
Тогда классImplicit
содержащий / наследующий отImplicitDelete
будет иметь совершенно прекрасный неявный сгенерированный конструктор перемещения, который вызываетImplicitDelete
Копия ctor.
Так в чем же причинаImplicit
иметь возможность двигаться неявно иImplicitDelete
не быть в состоянии двигаться безоговорочно?
На практике, еслиImplicit
а такжеImplicitDelete
есть некоторые сверхмощные подвижные элементы (подумайтеvector<string>
), Я не вижу причин, по которымImplicit
должен быть значительно вышеImplicitDelete
в движении производительности.ImplicitDelete
мог бы еще копироватьExplicitDelete
от его неявного хода ctor - так же, какImplicit
делает сImplicitDelete
.
Мне это поведение кажется противоречивым. Я бы нашел более последовательным, если бы произошло одно из этих двух событий:
Компилятор обрабатывает как неявно, так и явно удаленные векторы перемещения:
ImplicitDelete
становится неmove-constructible
, какExplicitDelete
ImplicitDelete
удаленный ход ctor приводит к удаленному неявному движению ctor вImplicit
(так же, какExplicitDelete
делает это сImplicitDelete
)Implicit
становится неmove-constructible
Подборкаstd::move
строка совершенно не в моем примере кодаИли компилятор возвращается к копированию ctorтакже заExplicitDelete
:
ExplicitDelete
Копируем конструктор во всехmove
с, как и дляImplicitDelete
ImplicitDelete
получает правильный неявный ход ctor(Implicit
неизменен в этом сценарии)Выходные данные примера кода показывают, чтоExplicit
член всегда перемещен.Вот полностью рабочий пример:
#include <utility>
#include <iostream>
using namespace std;
struct Explicit {
// prints whether the containing class's move or copy constructor was called
// in practice this would be the expensive vector<string>
string owner;
Explicit(string owner) : owner(owner) {};
Explicit(const Explicit& o) { cout << o.owner << " is actually copying\n"; }
Explicit(Explicit&& o) noexcept { cout << o.owner << " is moving\n"; }
};
struct ExplicitDelete {
ExplicitDelete() = default;
ExplicitDelete(const ExplicitDelete&) = default;
ExplicitDelete(ExplicitDelete&&) noexcept = delete;
};
struct ImplicitDelete : ExplicitDelete {
Explicit exp{"ImplicitDelete"};
};
struct Implicit : ImplicitDelete {
Explicit exp{"Implicit"};
};
int main() {
ImplicitDelete id1;
ImplicitDelete id2(move(id1)); // expect copy call
Implicit i1;
Implicit i2(move(i1)); // expect 1x ImplicitDelete's copy and 1x Implicit's move
return 0;
}