| 維度 | 深拷貝 | 淺拷貝 |
|---|---|---|
| 定義 | 源對象與拷貝對象完全獨立,擁有各自的內存資源 | 源對象與拷貝對象共享同一份內存實體,僅變量名不同 |
| 修改影響 | 任一方修改不影響另一方 | 任一方修改直接影響另一方 |
| 典型類型 | 值類型:基本類型、結構體、枚舉 | 引用類型:類、陣列、字符串(特殊)、介面 |
| 內存模型 | 棧/堆上分配新內存塊,逐字節複製 | 僅複製引用/指標/句柄,指向同一堆對象 |
// C# 風格演示,C/C++ 同理
int source = int.MaxValue; // 2,147,483,647
int dest = source; // 深拷貝:dest 獲得獨立副本
dest = 1024; // 修改 dest
source = 2048; // 修改 source
// 結果:source=2048, dest=1024, 互不干擾
struct Point { public int X, Y; }
Point source = new Point(10, 20);
Point dest = source; // 整個結構體逐字段複製 (深拷貝)
dest.X = 20;
// 結果:source.X=10, dest.X=20
結構體賦值、參數傳遞、返回值均觸發完整內存拷貝。大結構體頻繁拷貝有性能開銷,可用 ref/指標優化。
class Point { public int X, Y; }
Point source = new Point(10, 20);
Point dest = source; // 淺拷貝:複製引用,指向同一堆對象
dest.X = 20;
// 結果:source.X=20, dest.X=20 (同一對象)
source/dest,存儲地址。賦值 dest = source 僅複製句柄中的地址值,堆對象不動。這就是淺拷貝本質。
Point dest = new Point(source.X, source.Y);
// 或
Point dest = new Point();
dest.X = source.X;
dest.Y = source.Y;
class Point : ICloneable {
public int X, Y;
public object Clone() {
return new Point { X = this.X, Y = this.Y }; // 深拷貝
}
}
// 使用
Point dest = (Point)source.Clone();
// BinaryFormatter / JSON / Protobuf
string json = JsonSerializer.Serialize(source);
Point dest = JsonSerializer.Deserialize(json);
// 優點:處理複雜對象圖、循環引用;缺點:性能較差、需可序列化
string s1 = "hello";
string s2 = s1; // 淺拷貝引用
s2 = "world"; // 重新賦值 → s2 指向新字符串,s1 不變
// 字符串不可變:任何「修改」操作 (Substring, Replace, +) 都返回新字符串
// 因此表現如值類型,但底層仍是引用
int[] arr1 = {1,2,3};
int[] arr2 = arr1; // 淺拷貝
arr2[0] = 99; // arr1[0] 也變成 99
// 深拷貝方法:
int[] arr3 = (int[])arr1.Clone(); // 一維陣列 Clone() 為深拷貝
int[] arr4 = new int[arr1.Length];
Array.Copy(arr1, arr4, arr1.Length); // 手動複製
// 多維/交錯陣列 Clone() 仍為淺拷貝,需遞歸複製
List list1 = new List {1,2,3};
List list2 = list1; // 淺拷貝
List list3 = new List(list1); // 構造函數複製元素 (值類型元素即深拷貝)
List list4 = ...; // 引用類型元素:new List(list) 仍共享元素對象!
// 需元素級深拷貝:
List list5 = list4.Select(p => (Point)p.Clone()).ToList();
| 場景 | C 語言 | C++ (默認) | C++ (自定義) |
|---|---|---|---|
| 結構體賦值 | 逐字節複製 (深拷貝) | 逐成員複製 (深拷貝) | 可重載 operator= 實現淺/深邏輯 |
| 指標賦值 | 複製地址 (淺拷貝) | 複製地址 (淺拷貝) | 智能指標 shared_ptr(共享) / unique_ptr(移動/不可複製) |
| 含指標成員結構體 | 逐字節複製指標值 (淺拷貝指標指向的內存!) | 默認逐成員複製指標 (淺拷貝) | 必須實現拷貝構造函數和拷貝賦值運算符執行深拷貝 (Rule of Three/Five) |
| 標準庫容器 | — | vector/string 深拷貝元素 | 同上 |
Clone() 是否提供?=delete,僅支援移動)。shared_ptr/copy-on-write/flyweight 模式。深拷貝與淺拷貝的本質差異在於內存所有權與獨立性:
Clone()、拷貝構造函數、序列化等才能深拷貝。理解這一機制,是寫出無內存洩漏、無數據競爭、無意外副作用代碼的基石。下次見到 a = b,請先問自己:這是複製了數據,還是複製了引用?