コピーできない変数(std::atomic<int>
など)のメンバー初期化を実行する場合、回答 here に従って、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
を使用してコンパイルすると失敗しました。ここでどちらが正しいですか?
C++ 17以降、動作が変更され、コンパイラが_std::atomic<int> a = 0;
_でのコピー/移動の構築を省略している、つまり 保証コピーが必要)省略 。
(強調鉱山)
次の状況では、コピー/移動コンストラクターとデストラクタに目に見える副作用がある場合でも、コンパイラはクラスオブジェクトのコピーと移動の構築を省略する必要があります。オブジェクトは、他の方法でコピー/移動されるストレージに直接構築されます。 コピー/移動コンストラクターが存在またはアクセス可能である必要はありません。言語規則により、概念的にもコピー/移動操作が行われないことが保証されているため/:
詳細には、_std::atomic<int> a = 0;
_は コピーの初期化 を実行します。
Tがクラス型であり、その他の型のcv非修飾バージョンがTでないか、Tから派生していない場合、またはTが非クラス型であるが、その他の型がクラス型である場合、ユーザー定義の変換シーケンスotherの型からT(またはTがクラス型で変換関数が利用可能な場合はTから派生した型)に変換できるものが調べられ、オーバーロードの解決を通じて最適なものが選択されます。変換の結果は、変換コンストラクターが使用された場合は
prvalue temporary (until C++17)
prvalue expression (since C++17)
であり、オブジェクトを直接初期化するために使用されます。
そして
(強調鉱山)
tがクラス型であり、イニシャライザがcv非修飾型がTと同じクラスであるprvalue式である場合、一時マテリアライズドではなく、初期化式自体が宛先を初期化するために使用されますオブジェクト
つまり、a
は_0
_から直接初期化され、構築されるtemporaryがないため、temporaryからコピー/移動します。
C++ 17より前のコンセプトでは、_std::atomic<int> a = 0;
_は_std::atomic
_から一時的な_0
_を作成する必要があり、一時ファイルはa
のコピー作成に使用されます。
copy elision はC++ 17より前でも使用できますが、最適化と見なされます。
(強調鉱山)
これは最適化です。それが行われ、copy/
move (since C++11)
コンストラクターが呼び出されない場合でも、それは存在し、アクセス可能でなければなりません(最適化がまったく行われなかったかのように)。プログラムの形式が正しくありません:
そのため、gccは_std::atomic<int> a = 0;
_のc ++ 17より前のモードで診断をトリガーします。
(強調鉱山)
注:上記のルールは最適化を指定していません。prvaluesおよびtemporariesのC++ 17コア言語仕様は、以前のC++リビジョンのものと基本的に異なります。コピー/移動する一時ファイルはなくなりました。 C++ 17の仕組みを説明する別の方法は、「非実体化された値の受け渡し」です。 prvaluesが返され、一時的を実体化することなく使用されます。
ところで、私は_g++ 6.5.0
_に_-std=c++17
_のバグがあると思います。そしてそれはそれ以降のバージョンで修正されました。
ここでどちらが正しいですか?
7.4.0は正しいです。この場合、コピーは省略できます。 (ただし、これには c ++ 17 が必要です)。
(詳細は https://en.cppreference.com/w/cpp/language/copy_initialization を参照)