#c #gcc #c 17 #copy-elision
#c #gcc #c 17 #исключение копирования
Вопрос:
Я обнаружил, что в GCC 7 реализовано гарантированное исключение копирования, и я попробовал приведенный ниже код в wandbox:
#include <iostream>
struct NonMovable
{
NonMovable() noexcept = default;
NonMovable(NonMovableamp;amp;) noexcept = delete;
NonMovableamp; operator=(NonMovableamp;amp;) noexcept = delete;
};
NonMovable Make()
{
return {};
}
int main()
{
//[[maybe_unused]] const auto x = Make();
//const auto z = NonMovable{};
[[maybe_unused]] const auto y = NonMovable{NonMovable{}};
}
И я получил ошибку компиляции:
prog.cc: In function 'int main()':
prog.cc:20:60: error: use of deleted function 'NonMovable::NonMovable(NonMovableamp;amp;)'
[[maybe_unused]] const auto y = NonMovable{NonMovable{}};
^
prog.cc:6:5: note: declared here
NonMovable(NonMovableamp;amp;) noexcept = delete;
^~~~~~~~~~
Согласно cppreference:
При инициализации, если выражение инициализатора является значением prvalue, а cv-неквалифицированная версия исходного типа относится к тому же классу, что и класс назначения, выражение инициализатора используется для инициализации целевого объекта:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
Поэтому я думаю, что оно должно быть равно const Movable y{};
. Что не так?
Комментарии:
1. Похоже, что это ошибка GCC. Код хорошо компилируется в новой сборке GCC.
Ответ №1:
Инициализация списка не дает вам точного контроля над тем, что происходит. В принципе, комитет догадался, что программист может захотеть сделать, скорее всего, и присвоил соответствующие значения.
Если вы хотите иметь точный контроль, используйте инициализацию без списка. Для этого ваш тестовый кейс должен определенно работать.
Если вы придерживаетесь инициализации списка, то для агрегатов, я думаю, текущая редакция проекта сделает это и применит гарантированное копирование «elision», потому что они говорят
Если T является агрегированным классом, а список инициализаторов содержит один элемент типа cv U, где U — T или класс, производный от T, объект инициализируется из этого элемента (путем инициализации копирования для инициализации списка копирования или путем прямой инициализации для прямой инициализации списка).
Кроме того, вы можете получить то, что хотите, в будущей редакции стандарта или в разрешении отчета о дефектах даже для неагрегатов. Я считаю, что ваш класс является агрегированным, поэтому он должен компилироваться. Но, возможно, я чего-то здесь не хватает.
Комментарии:
1. » используйте инициализацию, отличную от списка. » было бы
const auto y = NonMovable(NonMovable());
? Если да, то это, похоже, тоже не работает.