web-dev-qa-db-ja.com

Visual Studio 2013および2015のC ++コンパイラエラーC2280「削除された関数を参照しようとしています」

このスニペットはVisual Studio 2013(バージョン12.0.31101.00 Update 4)でエラーなしでコンパイルされます

class A
{
public:
   A(){}
   A(A &&){}
};

int main(int, char*)
{
   A a;
   new A(a);
   return 0;
}

visual Studio 2015 RC(バージョン14.0.22823.1 D14REL)ではこのエラーでコンパイルされますが:

1>------ Build started: Project: foo, Configuration: Debug Win32 ------
1>  foo.cpp
1>c:\dev\foo\foo.cpp(11): error C2280: 'A::A(const A &)': attempting to reference a deleted function
1>  c:\dev\foo\foo.cpp(6): note: compiler has generated 'A::A' here
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Visual Studio 2015に同梱されているコンパイラーがコピーコンストラクターを生成し、=deleteそして、私はエラーC2280を受け取ります(ところで、msdn.Microsoft.comで文書化されたものを見つけることができません)。

今、Visual Studio 2013でコンパイル可能なコードベースがあり(コンパイラによって自動的に生成されたコードに依存しているため機能します)、C2280のためにVisual Studio 2015でコンパイルできないコードベースがあるとしましょう、どうすれば問題を修正できますか?

私はクラスAを次のように宣言することを考えていました:

class A
{
public:
   A(){}
   A(A &&){}
   A(const A&)=default;
};

私は何かが欠けていますか?

26

[class.copy]/7から、私の強調:

クラス定義でコピーコンストラクターが明示的に宣言されていない場合、非明示的なコンストラクターが暗黙的に宣言されます。 クラス定義が移動コンストラクターまたは移動代入演算子を宣言する場合、暗黙的に宣言されたコピーコンストラクターは、deleted;それ以外の場合は、デフォルト(8.4)として定義されます。後者のケースは、クラスにユーザーが宣言したコピー割り当て演算子またはユーザーが宣言したデストラクタがある場合は非推奨です。

パラグラフ18には、コピーの割り当てに類似した文言を持つ同等のセクションがあります。したがって、クラスは次のようになります。

class A
{
public:
   // explicit
   A(){}
   A(A &&){}

   // implicit
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};

それがあなたがそれをコピー構築できない理由です。移動コンストラクター/割り当てを提供し、それでもクラスをコピー可能にする場合は、これらの特別なメンバー関数を明示的に提供する必要があります。

    A(const A&) = default;
    A& operator=(const A&) = default;

また、移動割り当て演算子を宣言する必要があります。これらの特別な機能が本当に必要な場合は、おそらくデストラクタも必要になります。 Rule of Five を参照してください。

37
Barry

私は同じ問題を抱えていましたが、それは不十分に定義されたメンバー変数によるものでした:

double const deltaBase = .001;

これを配置すると、コピーコンストラクターが削除されます。 「const」を取り除き、コンストラクターで割り当てます。

22
doby

クラスにユーザー定義の移動コンストラクターを記述すると、コピーコンストラクターは削除されます。これは、クラスが移動コンストラクターに特別な動作を必要とする場合、おそらくコピーコンストラクターで同様の動作が必要になるため、コピーコンストラクターが削除されて、既定の動作を誤って使用しないようにするためです。

独自の移動コンストラクターを定義する場合andデフォルトのコピーコンストラクターを使用する場合、質問で提案したように、defaultとして宣言する必要があります。

class A
{
public:
   A(){}
   A(A &&){}
   //I know what I'm doing, compiler, use the default version.
   A(const A&)=default;
};

カスタム移動コンストラクターを定義する場合は、割り当て演算子とデストラクターについても考慮する必要があることに注意してください。

3
TartanLlama

コピーアクターを「デフォルト」にした後でも、このエラーが発生しました。結局、クラスメンバーの1人(rapidjsonのDocumentオブジェクト)がコピーを許可していませんでした。デフォルトのctorの初期化子リストの*(new rapidjson :: Document())で初期化された参照に変更しました。デフォルトのコピーctorに加えて、すべての個々のメンバーもコピー可能にする必要があるようです。

0
n-mam