อะไรคือความแตกต่างระหว่างสำเนาลึกกับสำเนาตื้น
อะไรคือความแตกต่างระหว่างสำเนาลึกกับสำเนาตื้น
คำตอบ:
สำเนาตื้นซ้ำให้น้อยที่สุด สำเนาตื้นของคอลเลกชันเป็นสำเนาของโครงสร้างการเก็บรวบรวมไม่ใช่องค์ประกอบ ด้วยสำเนาตื้นตอนนี้ทั้งสองคอลเลกชันแบ่งปันองค์ประกอบแต่ละ
สำเนาลึกทำซ้ำทุกอย่าง สำเนาที่ลึกของคอลเลกชันคือสองคอลเลกชันที่มีองค์ประกอบทั้งหมดในคอลเลกชันดั้งเดิมที่ซ้ำกัน
ความกว้างและความลึก; คิดในแง่ของต้นไม้อ้างอิงกับวัตถุของคุณเป็นรูทโหนด
ตื้น:
ตัวแปร A และ B อ้างถึงพื้นที่ต่าง ๆ ของหน่วยความจำเมื่อ B ถูกกำหนดให้กับ A ตัวแปรทั้งสองอ้างถึงพื้นที่หน่วยความจำเดียวกัน การปรับเปลี่ยนเนื้อหาของทั้งสองอย่างต่อมาจะปรากฏในเนื้อหาของคนอื่นทันทีในขณะที่แบ่งปันเนื้อหา
ลึก:
ตัวแปร A และ B อ้างถึงพื้นที่ต่าง ๆ ของหน่วยความจำเมื่อ B ถูกกำหนดให้กับค่าในพื้นที่หน่วยความจำซึ่งจุด A ที่จะถูกคัดลอกไปยังพื้นที่หน่วยความจำที่จุด B การดัดแปลงเนื้อหาของภายหลังนั้นยังคงไม่ซ้ำกับ A หรือ B เนื้อหาจะไม่ถูกแชร์
ในระยะสั้นมันขึ้นอยู่กับสิ่งที่ชี้ไปที่อะไร ในสำเนาตื้นวัตถุ B ชี้ไปยังตำแหน่งของวัตถุ A ในหน่วยความจำ ในสำเนาลึกทุกสิ่งในตำแหน่งหน่วยความจำของวัตถุ A จะถูกคัดลอกไปยังตำแหน่งหน่วยความจำของวัตถุ B
บทความ wiki นี้มีไดอะแกรมที่ยอดเยี่ยม
ลองพิจารณาภาพต่อไปนี้
ตัวอย่างเช่นObject.MemberwiseCloneสร้างลิงค์คัดลอกตื้น
และใช้อินเทอร์เฟซICloneableคุณสามารถรับสำเนาลึกตามที่อธิบายไว้ที่นี่
โดยเฉพาะอย่างยิ่งสำหรับนักพัฒนา iOS:
หากB
เป็นสำเนาตื้นของA
แล้วสำหรับข้อมูลดั้งเดิมที่มันต้องการB = [A assign];
และสำหรับวัตถุที่มันต้องการB = [A retain]
;
B และ A ชี้ไปที่ตำแหน่งหน่วยความจำเดียวกัน
หากB
เป็นสำเนาลึกของA
มันก็เป็นเช่นนั้นB = [A copy];
B และ A ชี้ไปยังตำแหน่งหน่วยความจำที่แตกต่างกัน
ที่อยู่หน่วยความจำ B เหมือนกับ A
B มีเนื้อหาเช่นเดียวกับของ
คัดลอกตื้น: คัดลอกค่าสมาชิกจากวัตถุหนึ่งไปอีกวัตถุหนึ่ง
Deep Copy: คัดลอกค่าสมาชิกจากวัตถุหนึ่งไปยังอีกวัตถุหนึ่ง
วัตถุตัวชี้ใด ๆ จะทำซ้ำและคัดลอกแบบลึก
ตัวอย่าง:
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.)
ฉันไม่ได้เห็นคำตอบสั้น ๆ และเข้าใจง่ายที่นี่ - ดังนั้นฉันจะลองดู
ด้วยการคัดลอกตื้นวัตถุใด ๆ ที่ชี้ไปยังต้นทางจะถูกชี้ไปยังปลายทางด้วย (เพื่อไม่ให้คัดลอกวัตถุที่อ้างอิง)
ด้วยการทำสำเนาแบบลึกวัตถุใด ๆ ที่ชี้ไปยังแหล่งที่มาจะถูกคัดลอกและสำเนานั้นจะถูกชี้ไปยังปลายทาง (ดังนั้นตอนนี้จะมี 2 ของแต่ละวัตถุที่อ้างอิง) สิ่งนี้จะซ้ำต้นไม้วัตถุ
เพื่อความเข้าใจง่ายคุณสามารถติดตามบทความนี้: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
คัดลอกตื้น:
สำเนาลึก:
{ลองนึกภาพวัตถุสองชิ้น: A และ B ที่มีประเภทเดียวกัน _t (เทียบกับ C ++) และคุณกำลังคิดเกี่ยวกับการคัดลอก A / B ที่ตื้น / ลึก}
คัดลอกตื้น: เพียงแค่ทำสำเนาของการอ้างอิงถึง A เป็น B. คิดว่ามันเป็นสำเนาที่อยู่ของ ดังนั้นที่อยู่ของ A และ B จะเหมือนกันนั่นคือที่อยู่เหล่านั้นจะถูกชี้ไปยังตำแหน่งหน่วยความจำเดียวกันนั่นคือเนื้อหาข้อมูล
Deep copy: เพียงทำสำเนาสมาชิกทั้งหมดของ A จัดสรรหน่วยความจำในตำแหน่งอื่นสำหรับ B แล้วมอบหมายสมาชิกที่คัดลอกไปที่ B เพื่อให้ได้สำเนาลึก ด้วยวิธีนี้หาก A กลายเป็น B ที่ไม่มีอยู่จริงยังคงใช้ได้ในหน่วยความจำ คำที่ถูกต้องที่จะใช้คือการโคลนนิ่งซึ่งคุณรู้ว่าพวกเขาทั้งคู่เหมือนกัน แต่แตกต่างกัน (เช่นเก็บไว้เป็นเอนทิตีที่แตกต่างกันสองอันในพื้นที่หน่วยความจำ) นอกจากนี้คุณยังสามารถให้ wrapper โคลนของคุณที่คุณสามารถตัดสินใจผ่านรายการรวม / การยกเว้นคุณสมบัติที่จะเลือกในระหว่างการคัดลอกลึก นี่เป็นวิธีปฏิบัติทั่วไปเมื่อคุณสร้าง API
คุณสามารถเลือกที่จะทำสำเนาตื้นONLY_IF ที่คุณเข้าใจสเตคที่เกี่ยวข้อง เมื่อคุณมีพอยน์เตอร์จำนวนมากที่ต้องจัดการกับใน C ++ หรือ C การทำสำเนาวัตถุตื้น ๆ นั้นเป็นความคิดที่ผิดจริงๆ
EXAMPLE_OF_DEEP COPY_ตัวอย่างคือเมื่อคุณพยายามทำการประมวลผลภาพและการรับรู้วัตถุคุณต้องปิดบัง "การเคลื่อนไหวที่ไม่เกี่ยวข้องและซ้ำซ้อน" ออกจากพื้นที่การประมวลผลของคุณ หากคุณใช้พอยน์เตอร์รูปภาพคุณอาจมีข้อกำหนดในการบันทึกอิมเมจหน้ากากเหล่านั้น ตอนนี้ ... ถ้าคุณทำสำเนาตื้นของภาพเมื่อตัวชี้อ้างอิงถูกฆ่าจากสแต็กคุณสูญเสียการอ้างอิงและสำเนาของมันนั่นคือจะมีข้อผิดพลาดรันไทม์ของการละเมิดการเข้าถึงในบางจุด ในกรณีนี้สิ่งที่คุณต้องการคือสำเนาที่มีความลึกของภาพโดยการปิดมัน ด้วยวิธีนี้คุณสามารถดึงมาสก์ได้ในกรณีที่คุณต้องการในอนาคต
EXAMPLE_OF_SHALLOW_COPYฉันไม่ได้มีความรู้มากเมื่อเทียบกับผู้ใช้ใน StackOverflow ดังนั้นโปรดลบส่วนนี้และวางตัวอย่างที่ดีถ้าคุณสามารถชี้แจง แต่ฉันคิดว่ามันเป็นความคิดที่ดีที่จะทำสำเนาตื้น ๆ ถ้าคุณรู้ว่าโปรแกรมของคุณจะทำงานในช่วงเวลาที่ไม่มีที่สิ้นสุดนั่นคือการดำเนินการ "push-pop" อย่างต่อเนื่องเหนือสแต็กด้วยการเรียกใช้ฟังก์ชัน หากคุณแสดงให้เห็นถึงบางสิ่งบางอย่างแก่ผู้สมัครเล่นหรือมือใหม่ (เช่นเนื้อหาการสอน C / C ++) ก็อาจไม่เป็นไร แต่ถ้าคุณใช้งานแอพพลิเคชั่นเช่นระบบตรวจจับและตรวจจับหรือระบบติดตามโซนาร์คุณไม่ควรทำการคัดลอกวัตถุที่อยู่รอบ ๆ เพราะมันจะฆ่าโปรแกรมของคุณไม่ช้าก็เร็ว
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
'ShallowCopy' ชี้ไปที่ตำแหน่งเดียวกันในหน่วยความจำเช่นเดียวกับ 'แหล่งที่มา' 'DeepCopy' ชี้ไปยังตำแหน่งอื่นในหน่วยความจำ แต่เนื้อหาเหมือนกัน
Shallow Copy คืออะไร
การคัดลอกตื้นเป็นสำเนาที่ชาญฉลาดของวัตถุ มีการสร้างวัตถุใหม่ที่มีสำเนาที่แน่นอนของค่าในวัตถุต้นฉบับ หากฟิลด์ใด ๆ ของวัตถุเป็นการอ้างอิงไปยังวัตถุอื่นจะคัดลอกเฉพาะที่อยู่อ้างอิงเท่านั้นเท่านั้นจะถูกคัดลอกที่อยู่หน่วยความจำ
ในรูปนี้MainObject1
มีเขตข้อมูลfield1
ชนิด int และชนิดContainObject1
ContainObject
เมื่อคุณทำสำเนาตื้นMainObject1
, MainObject2
ถูกสร้างขึ้นด้วยfield2
ที่มีมูลค่าการคัดลอกfield1
และยังคงชี้ไปที่ContainObject1
ตัวเอง หมายเหตุว่าตั้งแต่field1
เป็นชนิดดั้งเดิมค่าของมันจะถูกคัดลอกไปfield2
แต่เนื่องจากContainedObject1
เป็นวัตถุยังคงชี้ไปที่MainObject2
ContainObject1
ดังนั้นการเปลี่ยนแปลงใด ๆ ที่ทำContainObject1
ในจะปรากฏในMainObject1
MainObject2
ทีนี้ถ้านี่คือสำเนาตื้น ๆ ลองมาดูกันว่าสำเนาลึกคืออะไร?
Deep Copy คืออะไร
สำเนาลึกจะคัดลอกฟิลด์ทั้งหมดและทำสำเนาหน่วยความจำที่จัดสรรแบบไดนามิกที่ชี้ไปตามฟิลด์ การทำสำเนาแบบลึกจะเกิดขึ้นเมื่อวัตถุถูกคัดลอกพร้อมกับวัตถุที่มันอ้างถึง
ในรูปนี้ MainObject1 มีเขตข้อมูลfield1
ชนิด int และชนิดContainObject1
ContainObject
เมื่อคุณทำสำเนาลึกMainObject1
, MainObject2
ถูกสร้างขึ้นด้วยfield2
ที่มีมูลค่าการคัดลอกfield1
และมีความคุ้มค่าของการคัดลอกContainObject2
ContainObject1
โปรดทราบว่าการเปลี่ยนแปลงใด ๆ ที่ทำContainObject1
ในMainObject1
จะไม่ส่งผลMainObject2
ต่อ
field3
ที่เมื่ออยู่ในฐานะที่จะลองและเข้าใจบางสิ่งบางอย่างที่ลึกกว่าปัญหานั้น # 3 ในตัวอย่างนั้นเกิดขึ้นContainObject2
ที่ไหน
ในการเขียนโปรแกรมเชิงวัตถุชนิดรวมถึงชุดของเขตข้อมูลสมาชิก ฟิลด์เหล่านี้อาจถูกจัดเก็บตามค่าหรือตามการอ้างอิง (เช่นตัวชี้ไปยังค่า)
ในสำเนาแบบตื้นจะมีการสร้างอินสแตนซ์ใหม่ของประเภทและค่าจะถูกคัดลอกลงในอินสแตนซ์ใหม่ ตัวชี้การอ้างอิงจะถูกคัดลอกเช่นเดียวกับค่า ดังนั้นการอ้างอิงจึงชี้ไปยังวัตถุต้นฉบับ การเปลี่ยนแปลงใด ๆ กับสมาชิกที่เก็บไว้โดยการอ้างอิงจะปรากฏทั้งในต้นฉบับและสำเนาเนื่องจากไม่มีการทำสำเนาของวัตถุที่อ้างอิง
ในสำเนาลึกเขตข้อมูลที่เก็บโดยค่าจะถูกคัดลอกเหมือน แต่ตัวชี้ไปยังวัตถุที่เก็บไว้โดยอ้างอิงจะไม่ถูกคัดลอก แต่จะทำสำเนาลึกของวัตถุที่อ้างอิงและตัวชี้ไปยังวัตถุใหม่จะถูกเก็บไว้ การเปลี่ยนแปลงใด ๆ ที่ทำกับวัตถุที่อ้างอิงจะไม่มีผลกับสำเนาอื่น ๆ ของวัตถุ
'ShallowCopy' ชี้ไปที่ตำแหน่งเดียวกันในหน่วยความจำเช่นเดียวกับ 'แหล่งที่มา' 'DeepCopy' ชี้ไปยังตำแหน่งอื่นในหน่วยความจำ แต่เนื้อหาเหมือนกัน
การ
เลียนแบบตื้น:คำจำกัดความ: "สำเนาตื้นของวัตถุคัดลอกวัตถุ 'หลัก' แต่ไม่คัดลอกวัตถุภายใน เมื่อวัตถุที่กำหนดเอง (เช่นพนักงาน) มีเพียงดั้งเดิมตัวแปรชนิดสตริงจากนั้นคุณใช้การโคลนแบบตื้น
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
คุณกลับมาsuper.clone();
ที่เมธอด clone () ที่แทนที่และงานของคุณจบแล้ว
การโคลนลึก :
คำจำกัดความ: "ไม่เหมือนสำเนาตื้นสำเนาลึกเป็นสำเนาอิสระของวัตถุ"
หมายถึงเมื่อวัตถุพนักงานเก็บวัตถุที่กำหนดเองอื่น:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
จากนั้นคุณต้องเขียนรหัสเพื่อคัดลอกวัตถุ 'ที่อยู่' และในวิธีการแทนที่ () มิฉะนั้นวัตถุที่อยู่จะไม่ลอกแบบและจะทำให้เกิดข้อผิดพลาดเมื่อคุณเปลี่ยนค่าของที่อยู่ในการคัดลอกวัตถุของพนักงานซึ่งสะท้อนให้เห็นถึงวัตถุเดิมเช่นกัน
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
คัดลอกลึก
สำเนาลึกจะคัดลอกฟิลด์ทั้งหมดและทำสำเนาหน่วยความจำที่จัดสรรแบบไดนามิกที่ชี้ไปตามฟิลด์ การทำสำเนาแบบลึกจะเกิดขึ้นเมื่อวัตถุถูกคัดลอกพร้อมกับวัตถุที่มันอ้างถึง
คัดลอกตื้น
การคัดลอกตื้นเป็นสำเนาที่ชาญฉลาดของวัตถุ มีการสร้างวัตถุใหม่ที่มีสำเนาที่แน่นอนของค่าในวัตถุต้นฉบับ หากฟิลด์ใด ๆ ของวัตถุเป็นการอ้างอิงไปยังวัตถุอื่นเพียงคัดลอกที่อยู่อ้างอิงเท่านั้นเช่นคัดลอกที่อยู่หน่วยความจำเท่านั้น
Shallow Copy - ตัวแปรอ้างอิงภายในวัตถุดั้งเดิมและวัตถุที่คัดลอกตื้นมีการอ้างอิงถึงวัตถุทั่วไป
ลึกคัดลอก - ตัวแปรอ้างอิงภายในวัตถุเดิมและลึกคัดลอกมีการอ้างอิงถึงที่แตกต่างกันของวัตถุ
โคลนทำสำเนาตื้น ๆ เสมอ
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
}
เอาท์พุทข้างต้นจะเป็น -
จริงเท็จจริง
เท็จเท็จเท็จ
การเปลี่ยนแปลงใด ๆ ที่ทำในวัตถุดั้งเดิมจะสะท้อนให้เห็นในวัตถุตื้นไม่ได้อยู่ในวัตถุลึก
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
struct sample
{
char * ptr;
}
void shallowcpy(sample & dest, sample & src)
{
dest.ptr=src.ptr;
}
void deepcpy(sample & dest, sample & src)
{
dest.ptr=malloc(strlen(src.ptr)+1);
memcpy(dest.ptr,src.ptr);
}
ในเงื่อนไขอย่างง่ายสำเนาตื้นจะคล้ายกับ Call By Reference และสำเนาลึกคล้ายกับ Call By Value
ใน Call By Reference พารามิเตอร์ทั้งแบบเป็นทางการและตามจริงของฟังก์ชั่นหมายถึงตำแหน่งหน่วยความจำเดียวกันและค่า
ใน Call By Value ทั้งพารามิเตอร์ที่เป็นทางการและที่เกิดขึ้นจริงของฟังก์ชั่นหมายถึงตำแหน่งหน่วยความจำที่แตกต่างกัน แต่มีค่าเดียวกัน
ลองนึกภาพมีสองอาร์เรย์ที่เรียกว่า arr1 และ arr2
arr1 = arr2; //shallow copy
arr1 = arr2.clone(); //deep copy
สำเนาตื้นสร้างวัตถุผสมใหม่และแทรกการอ้างอิงลงในวัตถุต้นฉบับ
deepcopy สร้างวัตถุผสมใหม่และแทรกสำเนาของวัตถุต้นฉบับของวัตถุสารประกอบต้นฉบับ
ลองยกตัวอย่าง
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
โค้ดด้านบนจะพิมพ์เป็น FALSE
มาดูกันว่า
วัตถุประกอบดั้งเดิมx=[1,[2]]
(เรียกว่าเป็นสารผสมเนื่องจากมีวัตถุอยู่ภายในวัตถุ (Inception))
อย่างที่คุณเห็นในภาพนั่นคือรายการภายในรายการ
y = copy.copy(x)
จากนั้นเราก็สร้างสำเนาตื้นของมันโดยใช้ สิ่งที่หลามทำที่นี่คือมันจะสร้างวัตถุผสมใหม่ แต่วัตถุภายในพวกมันกำลังชี้ไปที่วัตถุดั้งเดิม
ในภาพมันได้สร้างสำเนาใหม่สำหรับรายการภายนอก แต่รายการภายในยังคงเหมือนเดิม
ตอนนี้เราสร้าง deepcopy z = copy.deepcopy(x)
มันใช้ สิ่งที่หลามทำที่นี่คือมันจะสร้างวัตถุใหม่สำหรับรายการภายนอกเช่นเดียวกับรายการภายใน ตามที่แสดงในภาพด้านล่าง (เน้นสีแดง)
ที่สิ้นสุดรหัสพิมพ์False
เป็น y และ z ไม่ใช่วัตถุเดียวกัน
HTH
การคัดลอกตื้นกำลังสร้างวัตถุใหม่แล้วคัดลอกเขตข้อมูลไม่คงที่ของวัตถุปัจจุบันไปยังวัตถุใหม่ ถ้าเขตข้อมูลเป็นประเภทค่า -> สำเนาของเขตข้อมูลจะดำเนินการ; สำหรับประเภทการอ้างอิง -> การอ้างอิงจะถูกคัดลอก แต่วัตถุที่อ้างอิงไม่ใช่; ดังนั้นวัตถุดั้งเดิมและโคลนอ้างอิงถึงวัตถุเดียวกัน
สำเนาลึกกำลังสร้างวัตถุใหม่แล้วคัดลอกเขตข้อมูลที่ไม่คงที่ของวัตถุปัจจุบันไปยังวัตถุใหม่ หากเขตข้อมูลเป็นประเภทค่า -> จะทำการคัดลอกฟิลด์เป็นบิต หากเขตข้อมูลเป็นประเภทการอ้างอิง -> จะทำการคัดลอกใหม่ของวัตถุที่อ้างอิง คลาสที่จะถูกโคลนต้องถูกแฟล็กเป็น [Serializable]
นำมาจาก [บล็อก]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
สำเนาลึกเกี่ยวข้องกับการใช้เนื้อหาของวัตถุหนึ่งเพื่อสร้างอินสแตนซ์อื่นของคลาสเดียวกัน ในสำเนาลึกวัตถุทั้งสองอาจมีข้อมูลเหมือนกัน ht แต่วัตถุเป้าหมายจะมีบัฟเฟอร์และทรัพยากรของตัวเอง การทำลายของวัตถุใดวัตถุหนึ่งจะไม่ส่งผลกระทบต่อวัตถุที่เหลืออยู่ ผู้ประกอบการที่ได้รับมอบหมายมากเกินไปจะสร้างสำเนาของวัตถุที่ลึก
การคัดลอกตื้นนั้นเกี่ยวข้องกับการคัดลอกเนื้อหาของวัตถุหนึ่งไปยังอีกอินสแตนซ์ของคลาสเดียวกันดังนั้นจึงสร้างภาพสะท้อน เนื่องจากการคัดลอกการอ้างอิงและพอยน์เตอร์โดยตรงวัตถุทั้งสองจะแบ่งปันเนื้อหาที่มีอยู่ภายนอกเดียวกันของวัตถุอื่นเพื่อคาดเดาไม่ได้
คำอธิบาย:
การใช้ตัวสร้างการคัดลอกเราเพียงคัดลอกค่าข้อมูลสมาชิกโดยสมาชิก วิธีการคัดลอกนี้เรียกว่าการคัดลอกตื้น ถ้าวัตถุนั้นเป็นคลาสที่เรียบง่ายประกอบด้วยประเภทที่สร้างขึ้นในตัวและไม่มีตัวชี้สิ่งนี้จะเป็นที่ยอมรับ ฟังก์ชั่นนี้จะใช้ค่าและวัตถุและพฤติกรรมของมันจะไม่ถูกแก้ไขด้วยสำเนาตื้นเฉพาะที่อยู่ของพอยน์เตอร์ที่เป็นสมาชิกจะถูกคัดลอกและไม่ใช่ค่าที่อยู่ชี้ไป ค่าข้อมูลของวัตถุจะถูกเปลี่ยนแปลงโดยฟังก์ชันโดยไม่ตั้งใจ เมื่อฟังก์ชันไม่ได้อยู่ในขอบเขตสำเนาของวัตถุที่มีข้อมูลทั้งหมดจะถูกดึงออกจากสแต็ก
หากวัตถุมีพอยน์เตอร์ใด ๆ จำเป็นต้องดำเนินการสำเนาลึก ด้วยสำเนาลึกของวัตถุหน่วยความจำจะถูกจัดสรรสำหรับวัตถุในร้านค้าฟรีและองค์ประกอบที่ชี้ไปจะถูกคัดลอก สำเนาลึกใช้สำหรับวัตถุที่ส่งคืนจากฟังก์ชัน
หากต้องการเพิ่มคำตอบอื่น ๆ
การคัดลอกตื้นจะไม่สร้างการอ้างอิงใหม่ แต่การทำสำเนาแบบลึกจะสร้างการอ้างอิงใหม่
นี่คือโปรแกรมที่จะอธิบายสำเนาลึกและตื้น
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 + "]";
}
}
คัดลอก ararys:
Array เป็นคลาสซึ่งหมายความว่ามันเป็นชนิดอ้างอิงดังนั้น array1 = array2 ส่งผลให้เกิดตัวแปรสองตัวที่อ้างอิงถึงอาร์เรย์เดียวกัน
แต่ดูตัวอย่างนี้:
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]);
}
โคลนตื้นหมายถึงเฉพาะคัดลอกหน่วยความจำที่ถูกโคลนอาร์เรย์
ถ้าอาร์เรย์ประกอบด้วยวัตถุประเภทค่าค่าที่จะถูกคัดลอก ;
ถ้าอาร์เรย์ประกอบด้วยชนิดอ้างอิงอ้างอิงเท่านั้นจะถูกคัดลอก - เพื่อให้เป็นผลให้มีสองอาร์เรย์ที่มีสมาชิกอ้างอิงวัตถุเดียวกัน
ในการสร้างสำเนาลึกที่ซึ่งชนิดการอ้างอิงถูกทำซ้ำคุณต้องวนซ้ำอาร์เรย์และโคลนแต่ละองค์ประกอบด้วยตนเอง
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) ไปยังวัตถุเป้าหมายและประเภทการอ้างอิงของวัตถุ (สตริงคลาส ฯลฯ ) จะถูกคัดลอกเป็นการอ้างอิงในวัตถุเป้าหมาย ในประเภทการอ้างอิงเป้าหมายนี้จะชี้ไปที่ตำแหน่งหน่วยความจำของวัตถุต้นฉบับ
สำเนาลึกคัดลอกค่าของวัตถุและประเภทการอ้างอิงลงในสำเนาใหม่ที่สมบูรณ์ของวัตถุเป้าหมาย ซึ่งหมายความว่าทั้งประเภทค่าและประเภทการอ้างอิงจะถูกจัดสรรไปยังที่ตั้งหน่วยความจำใหม่
การเพิ่มคำจำกัดความทั้งหมดข้างต้นหนึ่งสำเนาที่ใช้กันอย่างแพร่หลายมากที่สุดนั้นอยู่ในตัวสร้างการคัดลอก (หรือตัวดำเนินการกำหนดค่ามากเกินไป) ของคลาส
Shallow copy -> คือเมื่อคุณไม่ได้ให้ตัวสร้างการคัดลอก ที่นี่เฉพาะวัตถุที่ได้รับการคัดลอก แต่ไม่ได้คัดลอกสมาชิกของคลาสทั้งหมด
Deep copy -> คือเมื่อคุณตัดสินใจที่จะใช้ตัวสร้างการคัดลอกหรือการมอบหมายงานเกินพิกัดในชั้นเรียนของคุณและอนุญาตให้คัดลอกสมาชิกทั้งหมดของชั้นเรียน
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 ++ ก่อสร้าง