Инициализация члена для непереписываемой переменной в C ++ 17 - PullRequest
16 голосов
/ 30 сентября 2019

При выполнении инициализации элемента для непереписываемой переменной (например, std::atomic<int>) требуется использовать direct-initialization вместо copy-initialization в соответствии с ответом здесь . Однако, когда я включаю -std=c++17 в g++ 7.4.0, кажется, что последний тоже хорошо работает.

#include <atomic>

class A {
    std::atomic<int> a = 0;     // copy-initialization
    std::atomic<int> b{0};      // direct-initialization
};
$ g++ -c atomic.cc -std=c++11    // or c++14
atomic.cc:4:26: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
     std::atomic<int> a = 0;     // copy-initialization

$ g++ -c atomic.cc -std=c++17
// no error

Он также не удался при компиляции с g++ 6.5.0 даже с -std=c++17. Какой из них правильный здесь?

Ответы [ 2 ]

16 голосов
/ 30 сентября 2019

Поведение изменилось с 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;и это было исправлено в более поздней версии.

3 голосов
/ 30 сентября 2019

Какой из них является правильным здесь?

7.4.0 является правильным. Копия может быть исключена для этого случая, поэтому она в порядке. (хотя для этого требуется ).

(подробнее см. https://en.cppreference.com/w/cpp/language/copy_initialization)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...