Поведение изменилось с C ++ 17, что требует компиляторов, чтобы опустить конструкцию копирования / перемещения в std::atomic<int> a = 0;
, то есть гарантированное разрешение копирования .
(выделение мое)
При следующих обстоятельствах компиляторы обязаны опустить копирование и переместить конструкцию объектов класса, даже если конструктор копирования / перемещения и деструктор имеют наблюдаемыепобочные эффекты. Объекты создаются непосредственно в хранилище, где они в противном случае были бы скопированы / перемещены. Конструкторы копирования / перемещения не обязательно должны присутствовать или быть доступными, поскольку языковые правила гарантируют, что операция копирования / перемещения не выполняется, даже концептуально :
Подробно, std::atomic<int> a = 0;
выполняет копирование инициализации :
Если T является типом класса, а cv-неквалифицированная версия типа other не является T или не получена из T, или если T не является-класса типа, но типом другого является тип класса, определяемые пользователем последовательности преобразования, которые могут преобразовывать из типа другого в T (или в тип, производный от T, если T является типом класса и доступна функция преобразования)рассматриваются и выбирается лучший из них по разрешению перегрузки. Результат преобразования, который равен prvalue temporary (until C++17)
prvalue expression (since C++17)
, если использовался конструктор преобразования, затем используется для прямой инициализации объекта.
и
(выделениемой)
, если T является типом класса и инициализатор является выражением prvalue, чей cv-неквалифицированный тип является тем же классом, что и T, само выражение инициализатора, а не временное материализованное изон используется для инициализации целевого объекта
Это означает, что a
инициализируется непосредственно из 0
, нет никакого временного , который должен быть построен, а затем больше не временное для копирования / перемещения.
До C ++ 17 в концепции std::atomic<int> a = 0;
требуется, чтобы временное std::atomic
было построено из 0
, затем используется временноекопировать-конструировать a
.
Даже копирование elision разрешено до C ++ 17, это рассматривается как оптимизация:
(выделено мной)
Это оптимизация: даже когда требуется ршнурок и конструктор copy / move (since C++11)
не вызывается, он все еще должен присутствовать и быть доступным (как если бы оптимизация вообще не происходила), в противном случае программа некорректна :
Именно поэтому gcc запускает диагностику в режиме pre-c ++ 17 для std::atomic<int> a = 0;
.
(выделено мной)
Примечание: в приведенном выше правиле не указана оптимизацияСпецификация основного языка C ++ 17 для значений и временных значений принципиально отличается от таковой в более ранних ревизиях C ++: больше нет временного для копирования / перемещения из . Другой способ описать механику C ++ 17 - это «нематериализованная передача значений»: prvalues возвращаются и используются без материализации временного .
Кстати: я полагаю, тамбыла ошибка в g++ 6.5.0
с -std=c++17
;и это было исправлено в более поздней версии.