Ответ 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.