web-dev-qa-db-ja.com

std :: atomic_intでの「削除された関数の使用」エラー

std::atomic_int変数を使用したい。私のコードには、次のものがあります。

#include <atomic>

std::atomic_int stop = 0;

int main()
{
    // Do something
}

そして、これは私にコンパイルエラーを与えます:

use of deleted function 'std::__atomic_base<_IntTp>::__atomic_base(const std::__atomic_base<_IntTp>&) [with _ITp = int]'
 std::atomic_int stop = 0;
                        ^

何が起こっているのか考えていますか?

24
Karnivaurus

コードは一時的なstd::atomic_int RHSでは、std::atomic_intコンストラクター(deleted)をコピーして、stopを初期化します。

std::atomic_int stop = std::atomic_int(0);

これは、ここで実行しているcopy-initialisationは、他の種類の初期化とまったく同じではないためです。

[C++11: 8.5/16]:初期化子のセマンティクスは次のとおりです[..]

初期化子が(括弧なしの)braced-init-listである場合、オブジェクトまたは参照はlist-initialized(8.5.4)です。

(これにより、この回答の最後にオプション3が可能になります)

[..]

宛先タイプが(おそらくcv修飾された)クラスタイプの場合:

  • 初期化がdirect-initializationの場合、またはcopy-initializationの場合cv-unqualified version ofソースタイプは、宛先のクラスと同じクラス、またはその派生クラスであり、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され(13.3.1.3)、最適なものがオーバーロード解決(13.3)によって選択されます)。そのように選択されたコンストラクターは、引数として初期化式または式リストを使用して、オブジェクトを初期化するために呼び出されます。コンストラクターが適用されない場合、またはオーバーロード解決があいまいな場合、初期化の形式は正しくありません。

(これはほとんどあなたのコードを説明していますが、完全ではありません。ここで重要なのは、おそらく直感に反して、std::atomic_intのコンストラクタは、あなたの場合はまったく考慮されません!)

  • それ以外の場合(つまり、残りのcopy-initializationの場合)、ソースタイプから宛先タイプに変換できるユーザー定義の変換シーケンス、または(変換の場合13.3.1.4で説明されているように、その派生クラスへの関数が列挙され、最適なものがオーバーロード解決(13.3)によって選択されます。変換が実行できないかあいまいな場合、初期化は不正です。 =選択された関数は、引数として初期化式を使用して呼び出されます。関数がコンストラクターである場合、呼び出しは宛先タイプのcv非修飾バージョンの一時を初期化します。一時はprvalueです。 呼び出しの結果(コンストラクターの場合の一時的なもの)は、上記の規則に従ってdirect-initializeに使用され、 copy-initializationの宛先。特定の場合、実装は、このdirect-initialization中間結果を初期化中のオブジェクトに直接構築する。 12.2、12.8を参照してください。

(これはあなたのシナリオです;したがって、コピーは省略できますが、それはまだ可能でなければなりません)

  • [..]

とにかく、ここに修正があります。 direct-initialisationまたはlist-initialisationを使用します。

std::atomic_int stop(0);     // option 1
std::atomic_int stop{0};     // option 2
std::atomic_int stop = {0};  // option 3