web-dev-qa-db-ja.com

C ++コピーコンストラクターがconstオブジェクトを使用する必要があるのはなぜですか?

つのルール の状態として、クラスのクラスコピーコンストラクターを定義する必要があることを理解しています。また、次のコードが示すように、コピーコンストラクターの引数は通常constであることに気付きます。

class ABC {
public:
    int a;
    int b;
    ABC(const ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

私の質問は、コピーコンストラクターの引数がconstでない場合にどうなるかです。

class ABC
{
    public:
    int a;
    int b;
    ABC(ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

コピーコンストラクタの引数がconstの場合、2番目の実装が失敗する場合があることを理解しています。また、コピーコンストラクターの引数がconstの場合、コピーされるオブジェクトは処理中にその内容を変更しません。ただし、一部の人々はまだ最初の実装ではなく2番目の実装を使用していることに気づきます。 2番目の実装が推奨される理由はありますか?

19
feelfree
  • 論理的には、コピーを作成したいだけのオブジェクトを変更しても意味がありませんが、このオブジェクトがコピーされた回数を保存したい場合など、場合によっては意味があることもあります。しかし、これはこの情報を格納するmutableメンバー変数で機能し、constオブジェクトでも変更できます(2番目の点はこのアプローチを正当化します)

  • Constオブジェクトのコピーを作成できるようにしたい。しかし、引数をconst修飾子で渡さない場合、constオブジェクトのコピーを作成できません...

  • 一時オブジェクトは右辺値であり、非constへの参照にバインドできないため、一時参照からコピーを作成できませんでした。より詳細な説明については、私はお勧めします 問題に関するハーブサッターの記事

24
JBL

クラスのコンシューマーが最後に期待するのは、コピーされたオブジェクトを変更するコピーコンストラクターです。したがって、常にconstとしてマークする必要があります。

11
Bathsheba

ここでconstが必要になる理由は2つあります。

  1. これにより、コピーを作成するときに誤って元のオブジェクトを「損傷」しないことが保証されます。これは、コピーを作成するときに元のオブジェクトを変更したくないためです。
  2. 基本的なオブジェクト以外のものを渡すことができます。たとえば、コンストラクタがオブジェクト自体でない場合は、たとえば式を参照するためです。

2番目のケースを例示するには:

_ class ABC
    {
       public:
           int a;
           int b;
       ABC(const ABC &other)
       { 
         a = other.a;
         b = other.b;
       }
       ABC operator+(const ABC &other)
       {
           ABC res;
           res.a = a + other.a;
           res.b = b + other.b;
           return res;
       }
    }

  ...
  ABC A;
  a.a = 1;
  a.b = 2;
  ABC B(a+a);
_

_a+a_はABC型の一時オブジェクトであるため、コンストラクタがABC(ABC &other)の場合、これはコンパイルされません。しかし、それがABC(const ABC &other)の場合、計算の一時的な結果を使用して、それを参照として渡すことができます。

8
Mats Petersson

他のいくつかの回答が指摘しているように、その引数を変更したコピーコンストラクターは不愉快な驚きです。しかし、それだけが問題ではありません。コピーコンストラクターは、temporariesの引数と共に使用されることがあります。 (例:関数からの戻り。)そして、説明されているように、一時への非const参照は飛ぶことはありません elsewhere SO。

5
Andrew Lazarus

コピーコンストラクターがパラメーターをconstとして指定しない場合、このフラグメントはコンパイルされません。

const ABC foo;
ABC bar(foo);
3
Paul Mitchell

コピーコンストラクターは、コピー元のオブジェクトを変更しないでください。そのため、constパラメーターではotherが優先されます。どちらも機能しますが、渡されたオブジェクトが関数によって変更されるべきではないことが明確に示されているため、constが推奨されます。

constはユーザー専用です。実際の実行可能ファイルには存在しません。

1
Serdalis

技術的な意味での「必須」ではありません。 非推奨になりました ですが、標準にはそのような獣さえいます。推論のリンクをたどってください。

私たちが期待するコピーのセマンティクスは、「テンプレート」を変更せず、すべての点でまったく同じであるクローンを提供することです。これにより、元のフォームを特定することが困難になります。

予想されていることですが、他の方法で行うコピークターがあると2度考えます。これはユーザーを驚かせ、バグを引き起こす可能性があります。そして欲求不満とノイズ、カウントを確認するために「auto_ptrのベクター」をググってみてください。

残りの質問は、「実装でオリジナルに触れないことを誓いますが、別の署名が必要です」です。では、どのような署名ですか? TとT&を試してみましょう。

Tは、コピーActorを使用可能にする必要があるため、ドロップアウトし、それを実装しています。再帰:recursionを参照してください。

それはT&を残す。これは実際には多くのケースで機能します。しかし、元のオブジェクトがたまたまconst形式で座っているか、一時的なものである場合は、失敗します。なぜ雨がまったく降らないという賢明なケースを妨げるのですか?

0
Balog Pal

コピーコンストラクターがソースインスタンスを変更してはならないという基本的な前提に加えて、この記事では、constを使用する実際の技術的な理由について詳しく説明します。

http://www.geeksforgeeks.org/copy-constructor-argument-const/

つまり、それと私は引用します:

"...コンパイラが作成した一時オブジェクトは非const参照にバインドできません..."

0
infinite-loop