2010-04-17 67 views
45

thể trùng lặp:
What is the difference between a deep copy and a shallow copy?bản sao sâu vs Sao chép Shallow

sự khác biệt giữa bản sao sâu và nông cạn là gì. Loại bản sao nào mà một nhà xây dựng bản sao thực hiện?

+2

Bản sao của http://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy –

+0

Câu hỏi thứ nhất là một số, nhưng tôi có thể 't tìm thấy thứ 2, mặc dù có thể là bởi vì nó không được nêu rõ. @Ankur: trong câu hỏi thứ hai của bạn, bạn có hỏi về nhà xây dựng bản sao mặc định không? – outis

+1

Các thuật ngữ sâu so với bản sao nông thường không được sử dụng trong C++, vì chúng không ánh xạ đặc biệt tốt cho ngôn ngữ. Trong Java và một số ngôn ngữ khác, sự khác biệt là hữu ích hơn vì ngữ nghĩa dựa trên tham chiếu của chúng, làm cho bản sao nông không thể tránh khỏi trong hầu hết các trường hợp. Trong C++, nơi các đối tượng được sao chép theo giá trị, các bản sao thật sự là rất hiếm, nhưng hàm tạo bản sao mặc định cũng sẽ không thực hiện một bản sao sâu. Các thuật ngữ không có ý nghĩa trong C++ – jalf

Trả lời

10

Ví dụ tinh túy về điều này là một mảng con trỏ tới cấu trúc hoặc đối tượng (có thể thay đổi).

A bản sao nông sao chép mảng và duy trì tham chiếu đến đối tượng ban đầu.

A bản sao sâu cũng sẽ sao chép (sao chép) các đối tượng để chúng không có liên quan đến bản gốc. Ngụ ý trong điều này là bản thân đối tượng được sao chép sâu. Đây là nơi mà nó trở nên khó khăn bởi vì không có cách nào thực sự để biết nếu một cái gì đó được sao chép sâu hay không.

Trình tạo bản sao được sử dụng để khởi tạo đối tượng mới với đối tượng đã tạo trước đó của cùng một lớp. Theo trình biên dịch mặc định đã viết một bản sao nông. Bản sao nông hoạt động tốt khi phân bổ bộ nhớ động không liên quan bởi vì khi phân bổ bộ nhớ động có liên quan thì cả hai đối tượng sẽ trỏ tới cùng một vị trí bộ nhớ trong heap, Do đó để loại bỏ vấn đề này, chúng tôi đã viết bản sao sâu để cả hai đối tượng đều có bản sao thuộc tính của riêng họ trong ký ức.

Để đọc chi tiết với các ví dụ và giải thích đầy đủ, bạn có thể xem bài viết Constructors and destructors.

Trình tạo bản sao mặc định cạn. Bạn có thể làm cho các nhà xây dựng bản sao của riêng bạn sâu hoặc nông, nếu thích hợp. Xem C++ Notes: OOP: Copy Constructors.

+3

Nó phải là * một mảng của ** con trỏ đến ** đối tượng có thể thay đổi được * –

+0

Ví dụ tốt là Boost :: GIL trong đó chế độ xem là bản sao nông của đối tượng hình ảnh (vùng chứa pixel). Bản sao cục bộ/tạm thời của các pixel được tạo khi chúng được truy cập thông qua đối tượng xem. – jiggunjer

46

sao chép Shallow:

Một số thành viên của bản sao chép có thể tham khảo các đối tượng tương tự như bản gốc:

class X 
{ 
private: 
    int i; 
    int *pi; 
public: 
    X() 
     : pi(new int) 
    { } 
    X(const X& copy) // <-- copy ctor 
     : i(copy.i), pi(copy.pi) 
    { } 
}; 

Ở đây, pi viên của bản gốc và sao chép X đối tượng sẽ cả điểm đến giống nhau int.


bản sao sâu:

Tất cả các thành viên của ban đầu được nhân bản (đệ quy, nếu cần thiết). Không có đối tượng chia sẻ:

class X 
{ 
private: 
    int i; 
    int *pi; 
public: 
    X() 
     : pi(new int) 
    { } 
    X(const X& copy) // <-- copy ctor 
     : i(copy.i), pi(new int(*copy.pi)) // <-- note this line in particular! 
    { } 
}; 

Ở đây, pi viên của bản gốc và sao chép đối tượng X sẽ trỏ đến int đối tượng khác nhau, nhưng cả hai có cùng giá trị.


Các constructor sao chép mặc định (được cung cấp tự động nếu bạn không cung cấp một mình) tạo ra các bản sao chỉ cạn.

Correction: Một số ý kiến ​​dưới đây đã chỉ đúng ra rằng nó là sai khi nói rằng các bản sao constructor mặc định luôn thực hiện một bản sao cạn (hoặc một bản sao sâu, cho rằng vấn đề). Cho dù một nhà xây dựng bản sao của loại tạo ra một bản sao nông, hoặc bản sao sâu, hoặc một cái gì đó ở giữa hai, phụ thuộc vào sự kết hợp của hành vi sao chép của mỗi thành viên; người tạo bản sao của một thành viên có thể được tạo ra để làm bất cứ điều gì nó muốn, sau khi tất cả.

Đây là những gì phần 12,8, khoản 8 của năm 1998 chuẩn C++ nói về các ví dụ mã trên:

Các ngầm được xác định sao chép constructor cho lớp X thực hiện một bản sao memberwise của subobjects của nó. [...] Mỗi đối tượng con được sao chép theo cách thích hợp với loại của nó: [...] [I] f subobject là loại vô hướng, toán tử gán nội trang được sử dụng .

+1

Đoạn khó hiểu dường như không đồng ý với yêu cầu in đậm của bạn rằng hàm tạo bản sao mặc định chỉ tạo bản sao nông. – UncleBens

+0

Điều gì khiến bạn nghĩ vậy? Tôi hiểu điều này như sau: Các thành viên của một số loại con trỏ là một subobject vô hướng, phải không?Và nếu bạn sao chép một con trỏ bằng cách sử dụng toán tử gán sẵn, điều đó có nghĩa là đối tượng được trỏ tới sẽ không được nhân bản, nhưng chỉ đơn giản là được trỏ đến bởi một con trỏ bổ sung. Vì vậy, bạn kết thúc với một bản sao nông. – stakx

+1

@stakx Bạn nói đúng, nhưng tôi nghĩ điều này minh họa rằng các thuật ngữ "bản sao sâu" và "bản sao nông" không đặc biệt hữu ích - thực ra tôi chưa bao giờ nghe chúng được các lập trình viên C++ kinh nghiệm sử dụng. –

2

Sao chép sâu nghĩa đen thực hiện bản sao sâu. Nó có nghĩa là, nếu lớp của bạn có một số trường được tham chiếu, giá trị của chúng sẽ được sao chép, chứ không phải bản thân tài liệu tham khảo. Ví dụ, nếu bạn có hai trường hợp của một lớp, A & B với các trường kiểu tham chiếu và thực hiện một bản sao sâu, việc thay đổi giá trị của trường đó trong A sẽ không ảnh hưởng đến giá trị trong B. Và ngược lại. Mọi thứ khác với bản sao nông, bởi vì chỉ các tham chiếu mới được sao chép, do đó, việc thay đổi trường này trong một đối tượng được sao chép sẽ ảnh hưởng đến đối tượng gốc.

Loại bản sao nào mà một nhà xây dựng sao chép thực hiện?

Phụ thuộc vào triển khai thực hiện. Điều này có nghĩa rằng không có quy tắc nghiêm ngặt về điều đó, bạn có thể thực hiện nó như một bản sao sâu hoặc bản sao nông, tuy nhiên theo như tôi biết nó là một thực tế phổ biến để thực hiện một bản sao sâu trong một nhà xây dựng bản sao. Một nhà xây dựng bản sao mặc định thực hiện một bản sao nông mặc dù.

Các vấn đề liên quan