Ответ 1
Поведение изменилось с C++ 17, который требует от компиляторов пропустить конструкцию копирования/перемещения в std::atomic<int> a = 0;
, т.е. гарантированное разрешение копирования.
(выделение мое)
При следующих обстоятельствах компиляторы должны опустить конструкцию объектов копирования и перемещения, даже если конструктор копирования/перемещения и деструктор имеют наблюдаемые побочные эффекты. Объекты создаются непосредственно в хранилище, где они в противном случае были бы скопированы/перемещены. Конструкторы копирования/перемещения не обязательно должны присутствовать или быть доступными, так как языковые правила гарантируют, что операция копирования/перемещения не выполняется, даже концептуально:
Подробно, std::atomic<int> a = 0;
выполняет инициализацию копирования:
Если T является типом класса и cv-неквалифицированная версия типа other не является T или не получена из T, или если T не является типом класса, но тип other является типом класса, определяемые пользователем последовательности преобразования которые могут преобразовывать из типа другого в T (или в тип, производный от T, если T является типом класса и доступна функция преобразования), и выбирается лучший из них с помощью разрешения перегрузки. Результат преобразования, который представляет собой
prvalue temporary (until C++17)
prvalue expression (since C++17)
, если использовался конструктор преобразования, затем используется для прямой инициализации объекта.
и
(выделение мое)
если T является типом класса и инициализатор является выражением prvalue, чей cv-unqualified тип является тем же классом, что и T, само выражение инициализатора, а не временное материализованное из него, используется для инициализации целевого объекта
Это означает, что a
инициализируется непосредственно из 0
, временное построение не требуется, а затем больше не требуется временное копирование/перемещение.
До C++ 17 в концепции std::atomic<int> a = 0;
требуется, чтобы временный std::atomic
создавался из 0
, тогда временный используется для копирования-построения a
.
Даже разрешение на копирование разрешено до C++ 17, это считается оптимизацией:
(выделение мое)
Это оптимизация: даже когда это происходит и конструктор copy/
move (since C++11)
не вызывается, он все равно должен присутствовать и быть доступным (как если бы оптимизация вообще не происходила), в противном случае программа плохо сформирована:
Вот почему gcc запускает диагностику в режиме до C++ 17 для std::atomic<int> a = 0;
.
(выделение мое)
Примечание: вышеприведенное правило не определяет оптимизацию: спецификация C++ 17 основного языка значений и временных значений принципиально отличается от таковой в более ранних ревизиях C++: больше нет временного элемента для копирования/перемещения из. Еще один способ описать механику C++ 17 - это "нематериализованная передача значений": значения возвращаются и используются без материализации временного.
BTW: I suppose there was a bug in [TG412] with [TG413]; and it has been fixed in later version.