web-dev-qa-db-ja.com

LLVMで暗黙的に削除されたコピーコンストラクターの呼び出し

C++ 11ルールに従って、6つのもの(デフォルトのコンストラクター、コンストラクターのコピー、コンストラクターの移動、代入のコピー、代入の移動、およびデストラクター)がデフォルトで生成されます。 2番目のルールでは、カスタムコピー、移動、またはデストラクターが定義されている場合、これらのデフォルトの操作は生成されません。しかし、それに続く私のコードではそうではありません。しかし、このコードはエラーでコンパイルに失敗します

call to implicitly deleted copy constructor of 'Uni'

Uniのコピーコンストラクタを独自に作成すると、すべて正常に動作します。 (参照のために与えられたコードでコメントされています)

どんな考えでも大歓迎です。

最後に、私はこれをLLVMコンパイラを備えたXcodeをMacで実行しています。

どうもありがとう...

#include <iostream>

class A
{
public:
    A(int i) :num{i}
    {
        std::clog<< "ctor  A() num = " << num << "\n";

    }
    A( A const &aRef)
    :num{aRef.num}
    {
        std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
    }

    int value()
    {
        return num;
    }

private:
    int num;

};
class Uni
{

public:
    Uni(A* aptr) : up{aptr}
    {
        std::clog << " ctor Uni value = " << up.get()->value() << "\n";
    }
    /*Uni(Uni const &uRef)
    {
        std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
        up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
    }*/
private:
    std::unique_ptr<A> up;

};

int main(int argc, const char * argv[])
{
    Uni one{new A{10}};
    Uni two{one}; //default copy ctor is implicitly deleted. why ?
}
37
cpp_hex

特別なメンバーの自動生成のためのC++ 11ルールは、投稿したほど簡単ではありません。最も重要な違いは、場合によっては、メンバーが暗黙的に宣言されているが、削除済みとして定義されていることです。それはあなたの場合に起こることです。

C++ 11、[class.copy]§11:

クラスXのデフォルトのコピー/移動コンストラクターは、Xが次の場合に削除済み(8.4.3)として定義されます。

  • 対応する非自明なコンストラクターを持つバリアントメンバーであり、Xはユニオンのようなクラスです。
  • クラスタイプM(またはその配列)の非静的データメンバは、Mの対応するコンストラクタに適用されるオーバーロード解決(13.3)の結果としてコピー/移動できないあいまいさや、デフォルトのコンストラクターから削除された、またはアクセスできない関数の場合)
  • オーバーロード解決(13.3)がBの対応するコンストラクターに適用されるため、コピーまたは移動できない直接または仮想ベースクラスBは、あいまいさまたは削除されるかアクセスできない関数になりますデフォルトのコンストラクター、
  • デフォルトのコンストラクタから削除された、またはアクセスできないデストラクタを持つ型の任意の直接または仮想ベースクラスまたは非静的データメンバ、
  • コピーコンストラクターの場合、右辺値参照型の非静的データメンバー、または
  • 移動コンストラクターの場合、非静的データメンバー、または移動コンストラクターを持たず、簡単にコピーできない型を持つ直接または仮想基本クラス。

(エンファシス鉱山)


より一般的には、自動生成されたクラスメンバーのルールは次のとおりです。

  • クラスにユーザー提供のコンストラクターがない場合、デフォルトのコンストラクターが宣言されます。

  • クラスにユーザー指定のコピーコンストラクターがない場合は、コピーコンストラクターが宣言されます。

  • クラスに{ユーザー提供のコピーまたは移動コンストラクター、ユーザー提供のコピーまたは移動割り当て演算子、ユーザー提供のデストラクタ}がない場合、移動コンストラクターが宣言されます(ただし、以下の(*)を参照)。

  • クラスにユーザー指定のコピー割り当て演算子がない場合は、コピー演算子が宣言されます。

  • クラスに{ユーザー提供のコピーまたは移動コンストラクター、ユーザー提供のコピーまたは移動割り当て演算子、ユーザー提供のデストラクタ}がない場合、移動割り当て演算子が宣言されます(ただし、下の(*)を参照)。

  • クラスにユーザー提供のデストラクタがない場合は、デストラクタが宣言されます。

自動的に宣言されたメンバーは、デフォルトとして定義するか(デフォルトの処理を行う)、削除するように定義することができます(使用しようとするとエラーが発生します)。経験則は、「デフォルトのバージョンが理にかなっている場合、デフォルトとして定義されます。それ以外の場合、削除されたものとして定義されます」です。

この文脈では、「意味がある」とは、「削除された、あいまいな、アクセスできない、または違法な関数を呼び出そうとしないこと」を意味します。たとえば、この回答の最初の部分で引用した標準ビットには、コピーコンストラクターにとって「意味をなさない」ものがリストされています。

さらに、クラスにユーザー指定の移動コンストラクターまたは移動割り当て演算子がある場合、自動的に宣言されたコピーコンストラクターまたはコピー割り当て演算子は、削除済みとして定義されます。

(*)自動的に宣言された移動コンストラクターまたは移動割り当て演算子が削除済みとして定義される場合、代わりにまったく宣言されません。このルールが存在するため、このようなクラスを移動しようとすると、エラーを生成する代わりに暗黙的にそのクラスをコピーすることにフォールバックします。

39
Angew