2017-02-08 24 views
0

私は、単にオブジェクトへの参照を渡すか、C++でオブジェクトのディープコピーを作成するのではなく、オブジェクトの浅いコピーを実際にどのような状況で作成したいのですか?C++でリファレンスの代わりにシャローコピーを使用する理由は?

私が理解しているのは、読み取り専用オブジェクトまたは不変オブジェクトがある場合は、単に参照を使用したいということです。オリジナルを変更せずにコピーを変更する必要がある場合や、一部のデータを別のメモリアドレス空間にマーシャリングする場合は、詳細コピーを作成します。

コピーケースのコピーでは、浅いコピーを使用することができます(オブジェクトに書き込んでディープコピーを終了する前に)が、浅いコピーを使用する理由がいくつかありますか?

編集:質問を明確にしようとしています。 (C++ 11を想定)

+0

あなたの例では、T&around、参照(または場合によってはポインタ)をルートオブジェクトに渡すことを話しています。 – vijay267

答えて

2

ここでテーブルの上に2つのオプションがある:

  1. 浅いコピーコンストラクタ/代入演算子を持つオブジェクト。

  2. コピーするのに費用がかかり、コピーできないオブジェクトがあります。 C++ 11の場合、コンストラクタ/代入演算子は浅くなります。

最終的にC++は価値重視の言語です。 C++ 17まで、これは次のような単純なものです:

T t = someFuncReturningT(); 

少なくとも理論的にはコピー/移動操作を引き起こします。 C++ 17の保証されたelisionはこれが起こらないことを保証しますが、それまではTへのコピー/移動を実行するとみなされます。確かに、ほとんどすべてのコンパイラがそれを削除します。しかし、理論的にはまだそこにある。

しかし、移動操作では、浅いコピーを持たないことはそれほど悪いことではありません。

浅いコピーと高価なコピー+浅い移動が必要な主な理由は、コピーが単なる「浅いコピー」ではないタイプの場合です。例えば、shared_ptr。コピーは単にポインタまたは2つをコピーするのではなく、あなたはまた、参照カウントをバンプします。確かに、これはタイプとしてshared_ptrの設計の結果です:オブジェクトの複数の所有者を許可する。

これを行う唯一の方法は、それらの所有者のそれぞれに独自のコピーがある場合です。したがって、コピーはその点で「浅く」なければなりません。

したがって、オブジェクトのデザインの一部である場合に利点があります。


プレC++ 11日間について言えば、浅いコピーが意味があります。ポストC++ 11では、安価な移動操作に頼ることができますが、プレC++ 11は使用できません。したがって、浅いコピーは、値によってオブジェクトを合理的に返す唯一の方法です。

+2

これは、「読取り専用オブジェクトまたは不変オブジェクトがあれば、単に参照を使用したいと思う」というOPの理解にどのように対処していますか? –

+0

@barakmanos:何を参照していますか?あなたが望む振る舞いをしていないので、裸の 'const char *'を使うことはできません。 –

+1

さて、OPは構造体やクラスを指していると仮定しています。用語*浅いコピー*はそれ以外のものにも有効ですか? –

-2

最初に私の頭に浮かぶのは、オブジェクトを動かすことです。

新しい演算子でクラス内にメモリを割り当てたとします。

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    void destroy() 
    { 
     delete [] data; 
    } 

    A (const A& copy) 
    { 
     data = copy.data; 
    } 


    int* data 
} 

このオブジェクトをコピーしたいとします。なぜすべてのデータをコピーするのではなく、データにポインタをコピーするだけです。

A calculateA() 
{ 
    A returnVal; 
    for (int i = 0; i < 50; i++) 
     returnVal.data[i] = i; 
    return returnVal; 
} 

この場合、浅いコピーが有利です。

A (const A& copy) 
{ 
    data = copy.data; 
} 

A newA = calculateA(); 
// do stuff with newA 
newA.destroy(); 

他にも何千もの理由があると確信しています。

コピーをダブルクリックしないようにするには、コピーをnullに設定します。

#include <iostream> 
#include <utility> 

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    ~A() 
    { 
     if (data) 
     delete [] data; 
    } 

    A (A& copy) 
    { 
     data = copy.data; 
     copy.data = nullptr; 
    } 

    int* data; 
}; 


int main() 
{ 
    A aVal; 
    for (int i = 0; i < 50; i++) 
     aVal.data[i] = i; 

    A anotherVal = aVal; 

    int i = 10; 
    while (i--) 
     std::cout << anotherVal.data[i]; 
} 
+0

私の間違いから学ぶように投票を説明してください。 –

+0

"*この場合は浅いコピーが有利かもしれません。*"あなたは浅いコピーが簡単に破られる方法を説明しました。あなたのケースでは、あなたは 'data'配列を2回*削除しようとします。 –

+0

その理由は、質問が「何が理由だろうか」と尋ねるので、私は「できる」と言いました。簡単なポインタチェックで簡単に回避できます。 –

0

次の例を想像してみて:

shared_ptr<T> p1(new T); 
... 
shared_ptr<T> p2 = p1; 

ここでP2は、P1の浅いコピーです。

shared_ptr<T> f() { 
    shared_ptr<T> p1(new T); 
    return p1; 
} 
+0

それは自動的にから移動されます。もちろん、C++ 11では。 –

+0

2番目の例では最初の例ではありません。 –

+0

権利はありますが、OPのポイントは(潜在的に)有効です。妥当な方法でオブジェクトを操作するには、厳密に浅いコピーが必要なわけではありません。 –

関連する問題