15

昨日、C# でのオブジェクトのコピーについて質問しましたが、ほとんどの回答は、ディープ コピーシャロー コピーの違いと、特定のコピー コンストラクター (または演算子、または関数) が両方のコピー バリアントのどちらであるかを明確にする必要があるという事実に焦点を当てていました。実装します。これは奇妙だと思います。

私は、コピーに大きく依存する言語である C++ で多くのソフトウェアを作成しましたが、複数のコピー バリアントが必要になることはありませんでした。私がこれまでに使用した唯一の種類のコピー操作は、「十分な深さのコピー」と呼んでいるものです。次のことを行います。

  • オブジェクトがメンバー変数の所有権を持っている場合 ( compositionを参照)、再帰的にコピーされます。
  • オブジェクトがメンバー変数に対する所有権を持たない場合 ( aggregationを参照)、リンクのみがコピーされます。

さて、私の質問は 3 つあります。

  • 1) オブジェクトが複数のコピーバリアントを必要とすることはありますか?
  • 2) コピー関数は、それが実装するコピーバリアントを明確にする必要がありますか?
  • 3) 余談ですが、私が「十分に深いコピー」と呼んでいるものについて、より適切な用語はありますか? 「ディープコピー」という用語の定義について、関連する質問をしました。
4

4 に答える 4

5

オブジェクトは、コピーする必要があるものだけをコピーする必要があります。この質問は言語に依存しないとマークされており、あなたは C++ について言及しましたが、私は C# の用語で説明することを好みます (それが私が最もよく知っている用語だからです)。ただし、概念は似ています。

値の型は構造体に似ています。それらはオブジェクト インスタンスに直接存在します。したがって、オブジェクトをコピーするときは、値の型をコピーするしかありません。したがって、通常、これらについて心配する必要はありません。

参照型はポインターのようなものであり、ここで注意が必要です。参照タイプが何であるかに応じて、ディープ コピーが必要な場合と不要な場合があります。一般的な経験則では、(オブジェクトのメンバーとしての) 参照型が外部オブジェクトの状態に依存する場合、それを複製する必要があります。そうでない場合は、そうである必要はありません。

もう 1 つの考え方は、外部からオブジェクトに渡されたオブジェクトは、おそらく複製すべきではないということです。クラスによって生成されたオブジェクトは、そうあるべきです。

わかりました、嘘をつきました。私の言いたいことを最もよく説明するので、C++を使用します。

class MyClass {
    int foo;
    char * bar;
    char * baz;

public: MyClass(int f, char * str) {
        this->foo = f;
        bar = new char[f];
        this->baz = str;
    }
};

このオブジェクトでは、2 つの文字列バッファーを処理する必要があります。最初のbarは、クラス自体によって作成および管理されます。オブジェクトを複製するときは、新しいバッファを割り当てる必要があります。

baz一方、そうであってはなりません。実際、そうするのに十分な情報がないため、できません。ポインターはコピーするだけです。

そしてもちろん、それfooはただの数字です。コピーするだけです。他に心配することはありません:)

要約すると、質問に直接答えるには:

  1. ほとんどの場合、いいえ。意味のあるコピー方法は 1 つしかありません。ただし、その方法はさまざまです。
  2. 直接ではありません。それを文書化することは良い考えですが、内部にあるものはすべて内部にとどめるべきです。
  3. まさに「ディープコピー」。(編集: ALMOST) 制御していないオブジェクトまたはポインターを複製しようとしないでください。そのため、ルールから除外されます :)
于 2010-07-28T07:32:50.987 に答える
5

「ディープ コピー」と「シャロー コピー」の違いは、実装の詳細としては理にかなっていますが、それを超えてリークすることを許可すると、一般に、他の方法でも現れる可能性が高い抽象化の欠陥を示します。

オブジェクトが、そこに含まれるオブジェクトの同一性以外のFoo不変の側面をカプセル化するためだけにオブジェクト参照を保持している場合、 の正しいコピーには、参照の複製またはカプセル化されたオブジェクトの複製への参照が含まれる可能性があります。Foo

オブジェクトが、 identity 以外Fooのオブジェクトの可変および不変の側面をカプセル化する目的だけでオブジェクト参照を保持しているが、そのオブジェクトへの参照がそれを変更する可能性のあるものにさらされることはない場合、同じ状況が適用されます。

オブジェクトが、 identity 以外Fooのオブジェクトの可変および不変の側面をカプセル化するためだけにオブジェクト参照を保持し、問題のオブジェクトが変更される場合、 の正しいコピーには、カプセル化されたオブジェクトの複製への参照が含まれている必要があります。物体。Foo

オブジェクトが、 ID を含むFooオブジェクトの不変の側面をカプセル化する目的だけでオブジェクト参照を保持している場合、 の正しいコピーには参照の複製が含まれている必要があります。複製されたオブジェクトへの参照を含めてはなりません。Foo

オブジェクトFooが、可変状態とオブジェクト ID の両方をカプセル化する目的でオブジェクト参照を保持している場合Foo、単独での正しいコピーを作成することはできません。の正しいコピーは、Fooそれがアタッチされているオブジェクトのセット全体を複製することによってのみ作成できます。

「浅いコピー」について話すのが理にかなっているのは、正しいコピーを作成する手順の 1 つとして不完全な操作が使用される場合だけです。それ以外の場合、オブジェクト参照にカプセル化された状態のタイプによって制御される、正しいコピーの「深さ」は 1 つだけです。

于 2012-08-29T23:10:08.450 に答える
2

ほとんどの C++ プログラマーは、通常、オブジェクトをコピーする方法が 1 つしかないという非常に正当な理由から、「浅いコピー」や「深いコピー」という用語を使用しません。これは特に C++ に当てはまります。コンパイラは、プログラマが使用するコピー コンストラクタを指定できる多くの状況でコピー コンストラクタを使用するためです。たとえば、次のようになります。

void f( std::string s );

文字列をコピーする方法をコンパイラに伝える方法はありません。

于 2010-07-28T07:48:30.037 に答える