ディープコピーとシャローコピーの違いは何ですか?
ディープコピーとシャローコピーの違いは何ですか?
回答:
浅いコピーはできるだけ複製しません。コレクションの浅いコピーは、要素ではなくコレクション構造のコピーです。浅いコピーでは、2つのコレクションが個々の要素を共有します。
ディープコピーはすべてを複製します。コレクションのディープコピーは、元のコレクションのすべての要素が複製された2つのコレクションです。
幅と深さ。オブジェクトをルートノードとする参照ツリーについて考えます。
浅い:
変数AとBは異なるメモリ領域を参照し、BがAに割り当てられている場合、2つの変数は同じメモリ領域を参照します。どちらか一方のコンテンツに対する後の変更は、コンテンツを共有しているため、すぐに他方のコンテンツに反映されます。
深い:
変数AとBはメモリの異なる領域を参照します。BがAに割り当てられると、Aが指すメモリ領域の値がBが指すメモリ領域にコピーされます。いずれかの内容に対する後の変更は、AまたはBに固有のままです。内容は共有されません。
要するに、何が何を指しているかによります。浅いコピーでは、オブジェクトBはメモリ内のオブジェクトAの場所を指します。ディープコピーでは、オブジェクトAのメモリロケーションにあるすべてのものがオブジェクトBのメモリロケーションにコピーされます。
このウィキの記事には素晴らしい図があります。
次の画像を検討してみてください
たとえば、Object.MemberwiseCloneは浅いコピーリンクを作成します
浅いコピー:あるオブジェクトから別のオブジェクトにメンバー値をコピーします。
ディープコピー:あるオブジェクトから別のオブジェクトにメンバー値をコピーします。
ポインターオブジェクトは複製され、ディープコピーされます。
例:
class String
{
int size;
char* data;
};
String s1("Ace"); // s1.size = 3 s1.data=0x0000F000
String s2 = shallowCopy(s1);
// s2.size =3 s2.data = 0X0000F000
String s3 = deepCopy(s1);
// s3.size =3 s3.data = 0x0000F00F
// (With Ace copied to this location.)
簡単に理解するために、この記事に従うことができます:https : //www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
浅いコピー:
ディープコピー:
{2つのオブジェクトを想像してください:(C ++に関して)同じタイプの_tのAとBであり、AからBへの浅い/深いコピーについて考えている}
浅いコピー: Aへの参照をBにコピーするだけです。それをAのアドレスのコピーと考えてください。したがって、AとBのアドレスは同じになります。つまり、同じメモリ位置、つまりデータの内容を指します。
ディープコピー: Aのすべてのメンバーのコピーを作成し、Bの別の場所にメモリを割り当ててから、コピーしたメンバーをBに割り当てて、ディープコピーを実現します。このようにして、Aが存在しなくなっても、Bはメモリ内で引き続き有効です。使用する正しい用語は、両方とも完全に同じであるが、異なる(つまり、2つの異なるエンティティとしてメモリスペースに格納される)ことを知っているクローンです。クローンラッパーを提供して、包含/除外リストを介して、ディープコピー中に選択するプロパティを決定することもできます。これは、APIを作成するときの一般的な方法です。
あなたはシャローコピーを行うことを選択することができますONLY_IFあなたが利害関係を理解しています。C ++またはCで扱うポインタが非常に多い場合、オブジェクトの浅いコピーを行うのは本当に悪い考えです。
EXAMPLE_OF_DEEP COPY_例として、画像処理とオブジェクト認識を実行しようとしているときに、「関連のない反復的な動き」を処理領域からマスクする必要があります。画像ポインタを使用している場合、それらのマスク画像を保存する仕様があるかもしれません。NOW ...画像の浅いコピーを行う場合、ポインタ参照がスタックから削除されると、参照とそのコピーが失われます。つまり、ある時点でアクセス違反のランタイムエラーが発生します。この場合、必要なのは、イメージを複製することによるイメージのディープコピーです。この方法で、将来必要になる場合に備えてマスクを取得できます。
EXAMPLE_OF_SHALLOW_COPY私はStackOverflowのユーザーに比べてあまり詳しくないので、この部分を削除して、明確にできれば良い例を示してください。しかし、プログラムが無限に実行されることがわかっている場合、つまり、関数呼び出しを伴うスタックでの連続的な「プッシュポップ」操作を知っている場合は、浅いコピーを行うのは良い考えではないと思います。アマチュアまたは初心者に何かをデモンストレーションしている場合(C / C ++のチュートリアルなど)、それはおそらく問題ありません。しかし、監視および検出システムやソナー追跡システムなどのアプリケーションを実行している場合は、オブジェクトを浅くコピーし続けることは、遅かれ早かれプログラムを強制終了するためです。
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
「ShallowCopy」は「Source」と同じメモリ内の場所を指します。'DeepCopy'はメモリ内の別の場所を指していますが、内容は同じです。
浅いコピーとは何ですか?
浅いコピーは、オブジェクトのビット単位のコピーです。元のオブジェクトの値の正確なコピーを持つ新しいオブジェクトが作成されます。オブジェクトのフィールドのいずれかが他のオブジェクトへの参照である場合、参照アドレスのみがコピーされます。つまり、メモリアドレスのみがコピーされます。
この図では、MainObject1
フィールドがあるfield1
int型の、およびContainObject1
タイプのをContainObject
。の浅いコピーを実行するとMainObject1
、MainObject2
はfield2
、のコピーされた値を含み、それ自体をfield1
指し示すように作成されContainObject1
ます。以来ことに留意されたいfield1
プリミティブ型であり、その値はにコピーされfield2
なくためContainedObject1
の目的であるが、MainObject2
まだを指しますContainObject1
。したがって、ContainObject1
inに加えられた変更はすべてMainObject1
に反映されMainObject2
ます。
これが浅いコピーである場合、深いコピーとは何かを見てみましょう。
ディープコピーとは
ディープコピーはすべてのフィールドをコピーし、フィールドによってポイントされる動的に割り当てられたメモリのコピーを作成します。ディープコピーは、オブジェクトが参照するオブジェクトとともにオブジェクトがコピーされるときに発生します。
この図では、MainObject1はフィールド持つfield1
int型のを、およびContainObject1
タイプのContainObject
。あなたはの深いコピーを行うとMainObject1
、MainObject2
使用して作成されたfield2
のコピーされた値を含むfield1
とContainObject2
のコピーされた値を含みますContainObject1
。ContainObject1
inに加えられた変更はにMainObject1
は反映されないことに注意してくださいMainObject2
。
field3
、その問題と同じくらい深く何かを試して理解する立場にあるときに言及していますが、その例の#3はどこで発生していContainObject2
ますか?
オブジェクト指向プログラミングでは、型にはメンバーフィールドのコレクションが含まれます。これらのフィールドは、値または参照(つまり、値へのポインタ)によって格納されます。
浅いコピーでは、タイプの新しいインスタンスが作成され、値が新しいインスタンスにコピーされます。参照ポインタも値と同じようにコピーされます。したがって、参照は元のオブジェクトを指しています。参照によって保存されたメンバーへの変更は、参照されたオブジェクトのコピーが作成されなかったため、オリジナルとコピーの両方に表示されます。
ディープコピーでは、値によって格納されるフィールドは以前と同様にコピーされますが、参照によって格納されるオブジェクトへのポインターはコピーされません。代わりに、参照オブジェクトのディープコピーが作成され、新しいオブジェクトへのポインターが格納されます。これらの参照オブジェクトに加えられた変更は、オブジェクトの他のコピーには影響しません。
浅いクローニング:
定義:「オブジェクトの浅いコピーは「メイン」オブジェクトをコピーしますが、内部オブジェクトはコピーしません。」カスタムオブジェクト(たとえば、従業員)がプリミティブなString型の変数のみを持っている場合は、Shallow Cloningを使用します。
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
super.clone();
オーバーライドされたclone()メソッドに戻り、ジョブが終了します。
ディープクローニング:
定義:「浅いコピーとは異なり、ディープコピーはオブジェクトの完全に独立したコピーです。」
Employeeオブジェクトが別のカスタムオブジェクトを保持することを意味します。
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
次に、オーバーライドされたclone()メソッドで 'Address'オブジェクトのクローンを作成するコードを記述する必要があります。そうでない場合、Addressオブジェクトは複製されず、複製されたEmployeeオブジェクトのAddressの値を変更するとバグが発生し、元の値も反映されます。
var source = { firstName="Jane", lastname="Jones" };
var shallow = ShallowCopyOf(source);
var deep = DeepCopyOf(source);
source.lastName = "Smith";
WriteLine(source.lastName); // prints Smith
WriteLine(shallow.lastName); // prints Smith
WriteLine(deep.lastName); // prints Jones
ディープコピー
ディープコピーはすべてのフィールドをコピーし、フィールドによってポイントされる動的に割り当てられたメモリのコピーを作成します。ディープコピーは、オブジェクトが参照するオブジェクトとともにオブジェクトがコピーされるときに発生します。
浅いコピー
浅いコピーは、オブジェクトのビット単位のコピーです。元のオブジェクトの値の正確なコピーを持つ新しいオブジェクトが作成されます。オブジェクトのフィールドのいずれかが他のオブジェクトへの参照である場合、参照アドレスのみがコピーされます。つまり、メモリアドレスのみがコピーされます。
浅いコピー -元のオブジェクトと浅いコピーのオブジェクト内の参照変数は、共通オブジェクトを参照しています。
ディープコピー -元のオブジェクトとディープコピーされたオブジェクト内の参照変数は、異なるオブジェクトを参照しています。
クローンは常に浅いコピーを行います。
public class Language implements Cloneable{
String name;
public Language(String name){
this.name=name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
メインクラスは次のとおりです-
public static void main(String args[]) throws ClassNotFoundException, CloneNotSupportedException{
ArrayList<Language> list=new ArrayList<Language>();
list.add(new Language("C"));
list.add(new Language("JAVA"));
ArrayList<Language> shallow=(ArrayList<Language>) list.clone();
//We used here clone since this always shallow copied.
System.out.println(list==shallow);
for(int i=0;i<list.size();i++)
System.out.println(list.get(i)==shallow.get(i));//true
ArrayList<Language> deep=new ArrayList<Language>();
for(Language language:list){
deep.add((Language) language.clone());
}
System.out.println(list==deep);
for(int i=0;i<list.size();i++)
System.out.println(list.get(i)==deep.get(i));//false
}
上記のOutPutは、
false true true
false false false
元のオブジェクトで行われた変更は、深いオブジェクトではなく浅いオブジェクトに反映されます。
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
OutPut- ViSuaLBaSiC C
正式な定義ではなく例を挙げたいと思います。
var originalObject = {
a : 1,
b : 2,
c : 3,
};
このコードは、浅いコピーを示しています。
var copyObject1 = originalObject;
console.log(copyObject1.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject1.a = 4;
console.log(copyObject1.a); //now it will print 4
console.log(originalObject.a); // now it will also print 4
var copyObject2 = Object.assign({}, originalObject);
console.log(copyObject2.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject2.a = 4;
console.log(copyObject2.a); // now it will print 4
console.log(originalObject.a); // now it will print 1
このコードはディープコピーを示しています。
var copyObject2 = Object.assign({}, originalObject);
console.log(copyObject2.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject2.a = 4;
console.log(copyObject2.a); // now it will print 4
console.log(originalObject.a); // !! now it will print 1 !!
1 1 4 4 4 4 4 4
浅いコピーは、新しい複合オブジェクトを構築し、その参照を元のオブジェクトに挿入します。
浅いコピーとは異なり、deepcopyは新しい複合オブジェクトを構築し、元の複合オブジェクトの元のオブジェクトのコピーも挿入します。
例を見てみましょう。
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
上記のコードはFALSEを出力します。
方法を見てみましょう。
元の複合オブジェクトx=[1,[2]]
(オブジェクト内にオブジェクトがあるため、複合と呼ばれます(開始))
画像でわかるように、リスト内にリストがあります。
次に、を使用してその浅いコピーを作成しy = copy.copy(x)
ます。ここでpythonが行うことは、新しい複合オブジェクトを作成しますが、それらの内部のオブジェクトは元のオブジェクトを指しています。
画像では、外側のリストの新しいコピーを作成しています。しかし、内部リストは元のリストと同じままです。
次に、を使用してそれのディープコピーを作成しz = copy.deepcopy(x)
ます。ここでのpythonの機能は、外部リストと内部リストの新しいオブジェクトを作成することです。下の画像に示すように(赤で強調表示)。
最後に、prints False
は、yとzが同じオブジェクトではないためです。
HTH。
浅いコピーとは、新しいオブジェクトを作成し、現在のオブジェクトの非静的フィールドを新しいオブジェクトにコピーすることです。フィールドが値タイプの場合->フィールドのビットごとのコピーが実行されます。以下のための基準タイプ - >参照がコピーされているが、参照されるオブジェクトはありません。したがって、元のオブジェクトとそのクローンは同じオブジェクトを参照します。
ディープコピーとは、新しいオブジェクトを作成し、現在のオブジェクトの非静的フィールドを新しいオブジェクトにコピーすることです。フィールドが値タイプの場合 ->フィールドのビットごとのコピーが実行されます。フィールドが参照タイプの場合 -> 参照されたオブジェクトの新しいコピーが実行されます。複製するクラスには、[Serializable]のフラグを付ける必要があります。
[ブログ]からの引用:http : //sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
ディープコピーでは、1つのオブジェクトのコンテンツを使用して、同じクラスの別のインスタンスを作成します。ディープコピーでは、2つのオブジェクトに同じ情報が含まれている場合がありますが、ターゲットオブジェクトには独自のバッファーとリソースがあります。どちらのオブジェクトを破棄しても、残りのオブジェクトには影響しません。多重定義された代入演算子は、オブジェクトの深いコピーを作成します。
浅いコピーでは、1つのオブジェクトの内容を同じクラスの別のインスタンスにコピーすることにより、ミラーイメージを作成します。参照とポインタを直接コピーするため、2つのオブジェクトは、他のオブジェクトと同じ外部に含まれるコンテンツを共有し、予測不能になります。
説明:
コピーコンストラクターを使用して、データ値をメンバーごとにコピーするだけです。このコピー方法は、浅いコピーと呼ばれます。オブジェクトが組み込み型で構成され、ポインターがない単純なクラスの場合、これは許容されます。この関数は値とオブジェクトを使用し、その動作は浅いコピーでは変更されません。メンバーであるポインターのアドレスのみがコピーされ、アドレスが指している値はコピーされません。その後、オブジェクトのデータ値が関数によって誤って変更されます。関数がスコープ外になると、すべてのデータを含むオブジェクトのコピーがスタックからポップされます。
オブジェクトにポインタがある場合、ディープコピーを実行する必要があります。オブジェクトのディープコピーでは、メモリが空きストアのオブジェクトに割り当てられ、ポイントされている要素がコピーされます。ディープコピーは、関数から返されるオブジェクトに使用されます。
浅いコピーは新しい参照を作成しませんが、深いコピーは新しい参照を作成します。
これは、深くて浅いコピーを説明するプログラムです。
public class DeepAndShollowCopy {
int id;
String name;
List<String> testlist = new ArrayList<>();
/*
// To performing Shallow Copy
// Note: Here we are not creating any references.
public DeepAndShollowCopy(int id, String name, List<String>testlist)
{
System.out.println("Shallow Copy for Object initialization");
this.id = id;
this.name = name;
this.testlist = testlist;
}
*/
// To performing Deep Copy
// Note: Here we are creating one references( Al arraylist object ).
public DeepAndShollowCopy(int id, String name, List<String> testlist) {
System.out.println("Deep Copy for Object initialization");
this.id = id;
this.name = name;
String item;
List<String> Al = new ArrayList<>();
Iterator<String> itr = testlist.iterator();
while (itr.hasNext()) {
item = itr.next();
Al.add(item);
}
this.testlist = Al;
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Oracle");
list.add("C++");
DeepAndShollowCopy copy=new DeepAndShollowCopy(10,"Testing", list);
System.out.println(copy.toString());
}
@Override
public String toString() {
return "DeepAndShollowCopy [id=" + id + ", name=" + name + ", testlist=" + testlist + "]";
}
}
アラリーのコピー:
配列はクラスです。つまり、それは参照型であるため、array1 = array2は同じ配列を参照する2つの変数になります。
しかし、この例を見てください:
static void Main()
{
int[] arr1 = new int[] { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 6, 7, 8, 9, 0 };
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = arr1;
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = (int[])arr1.Clone();
arr1[2] = 12;
Console.WriteLine(arr1[2] + " " + arr2[2]);
}
浅いクローンは、クローンされた配列によって表されるメモリのみがコピーされることを意味します。
配列に値タイプのオブジェクトが含まれている場合、値がコピーされます。
配列に参照型が含まれている場合は、参照のみがコピーされます。その結果、メンバーが同じオブジェクトを参照する2つの配列があります。
ディープコピーを作成するには、参照タイプが重複している場合、配列をループして各要素を手動で複製する必要があります。
private void button1_Click(object sender, EventArgs e) { int[] arr1 = new int[]{1,2,3,4,5}; int[] arr2 = new int[]{6,7,8,9,0}; MessageBox.Show(arr1[2] + " " + arr2[2]); arr2 = arr1; MessageBox.Show(arr1[2] + " " + arr2[2]); arr1[2] = 12; MessageBox.Show(arr1[2] + " " + arr2[2]); }
以下のことから理解できるようになりました。
浅いコピーは、オブジェクト値の型(int、float、bool)フィールドをターゲットオブジェクトにコピーし、オブジェクトの参照型(文字列、クラスなど)は、ターゲットオブジェクトの参照としてコピーされます。このターゲットでは、参照タイプはソースオブジェクトのメモリロケーションを指しています。
ディープコピーは、オブジェクトの値と参照型をターゲットオブジェクトの完全に新しいコピーにコピーします。つまり、値タイプと参照タイプの両方に新しいメモリ位置が割り当てられます。
上記のすべての定義に加えて、最も一般的に使用されるもう1つのディープコピーは、クラスのコピーコンストラクター(またはオーバーロード代入演算子)にあります。
浅いコピー->は、コピーコンストラクターを提供しない場合です。ここでは、オブジェクトのみがコピーされ、クラスのすべてのメンバーはコピーされません。
ディープコピー->は、クラスにコピーコンストラクターまたはオーバーロードの割り当てを実装することを決定し、クラスのすべてのメンバーのコピーを許可する場合です。
MyClass& MyClass(const MyClass& obj) // copy constructor for MyClass
{
// write your code, to copy all the members and return the new object
}
MyClass& operator=(const MyClass& obj) // overloading assignment operator,
{
// write your code, to copy all the members and return the new object
}
コピーコンストラクターは、同じクラスの以前に作成されたオブジェクトで新しいオブジェクトを初期化するために使用されます。デフォルトでは、コンパイラは浅いコピーを書き込みました。動的メモリ割り当てが関係していない場合、浅いコピーは正常に機能します。動的メモリ割り当てが関係している場合、両方のオブジェクトがヒープ内の同じメモリ位置を指すため、この問題を取り除くために、両方のオブジェクトが独自の属性のコピーを持つように深いコピーを作成しましたメモリ内。詳細な例と説明を読むには、C ++コンストラクターの記事を参照してください。