| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |
- 3d모델링
- 카드뉴스
- Photoshop
- 포토샵
- AI
- cs기초
- 자바스크립트
- blender4.0
- 비트연산
- 알고리즘
- Python
- 백준
- 프로그래머스
- level1
- blender
- c언어
- 코딩테스트
- 단계별로 풀어보기
- 블렌더튜토리얼
- 도넛튜토리얼
- leetcode
- 블렌더도넛
- csharp
- CS
- boj
- 블렌더
- 파이썬
- 단계별문제풀이
- 3D그래픽
- 3d스터디
- Today
- Total
슬로우도파민
[C# 이해하기] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy) 본문
“복사”라고 하면 보통 “완전히 똑같은 걸 하나 더 만든다”를 떠올립니다.
하지만 C#에서 복사는 생각보다 단순하지 않습니다. 왜냐하면 객체 안에 또 다른 객체(참조형)가 들어있을 수 있기 때문입니다.
그래서 복사에는 크게 두 가지가 있습니다.
- 얕은 복사(Shallow Copy): 겉은 새로 만들지만, 안쪽 참조는 그대로 공유
- 깊은 복사(Deep Copy): 안쪽 참조까지 새로 만들어 완전히 독립

1) 먼저, “복사 문제”가 왜 생기나?
값 형식(int, float 등)은 복사하면 그냥 값이 복사되니 직관적입니다.
문제는 참조 형식(class, 배열, List 등)입니다.
참조 형식의 객체는 “겉(객체)” 안에 필드들이 있고, 그 필드 중 일부가 또 다른 객체를 가리킬 수 있습니다.
즉, 이런 구조가 가능합니다.
- Player 객체
- Level (int)
- Inventory (int[] 배열) ← 또 다른 참조형
이때 “Player를 복사했다”는 말이 Inventory도 새로 복사했다는 뜻인지가 애매해집니다.
이 애매함을 정리한 개념이 얕은 복사/깊은 복사입니다.
2) 정의
- 얕은 복사: “겉 껍데기만 새로 만들고, 내부의 참조형은 같이 쓴다”
- 깊은 복사: “내부의 참조형까지 새로 만들어서, 완전히 따로 쓴다”
3) 얕은 복사 예시: 겉은 둘, 속은 공유
class Player
{
public int Level;
public int[] Inventory; // 참조형(배열)
}
var p1 = new Player { Level = 1, Inventory = new[] { 10, 20 } };
// 얕은 복사(의미): Player는 새로 만들었지만 Inventory는 공유
var p2 = new Player { Level = p1.Level, Inventory = p1.Inventory };
p2.Level = 99; // p2의 값 필드만 변경
p2.Inventory[0] = 777; // 공유된 배열을 변경
Console.WriteLine(p1.Level); // 1 (영향 없음)
Console.WriteLine(p1.Inventory[0]); // 777 (영향 있음)
왜 이런 일이 생길까?
Inventory는 배열이고(참조형), p1.Inventory를 그대로 넣으면 p2.Inventory도 같은 배열을 가리키게 됩니다.
4) 깊은 복사 예시: 내부까지 새로 만들어 독립
var p3 = new Player
{
Level = p1.Level,
Inventory = (int[])p1.Inventory.Clone() // 배열 자체를 새로 복사
};
p3.Inventory[0] = 123;
Console.WriteLine(p1.Inventory[0]); // 777 (p3와 무관)
Console.WriteLine(p3.Inventory[0]); // 123
여기서는 Inventory 배열도 새로 만들었기 때문에, p3는 p1과 독립적입니다.
5) 심화 : “Clone() 했는데도 공유가 남는 경우”
배열이 int[]처럼 값형을 담으면 Clone()이 꽤 안전합니다.
그런데 배열이 Item[]처럼 참조형 객체를 담는 배열이면 얘기가 달라집니다.
class Item { public string Name; }
class Bag { public Item[] Items; }
var b1 = new Bag { Items = new[] { new Item { Name = "Potion" } } };
var b2 = new Bag { Items = (Item[])b1.Items.Clone() }; // 배열만 새로, Item은 공유
b2.Items[0].Name = "Elixir";
Console.WriteLine(b1.Items[0].Name); // Elixir (같이 바뀜)
여기서 Clone()은 “배열”은 새로 만들지만, 배열 안의 Item 객체까지 새로 만들지는 않습니다.
그래서 b1.Items[0]과 b2.Items[0]이 같은 Item 객체를 가리키는 공유 상태가 됩니다.
“진짜 깊은 복사”로 고치면 이렇게 됩니다
배열만 복사하지 말고, 각 Item도 새로 만들어 담아야 합니다.
var b3 = new Bag
{
Items = b1.Items.Select(item => new Item { Name = item.Name }).ToArray()
};
b3.Items[0].Name = "Elixir";
Console.WriteLine(b1.Items[0].Name); // Potion ← 안 바뀜
Console.WriteLine(b3.Items[0].Name); // Elixir
핵심은 이 한 줄입니다.
- 얕은 복사: Items = (Item[])b1.Items.Clone() (Item 공유)
- 깊은 복사: Items = b1.Items.Select(item => new Item{...}).ToArray() (Item도 복제)
“배열 요소가 값형이면?”
만약 Items가 int[] 같은 값형 배열이라면, Clone()만으로도 사실상 깊은 복사처럼 동작합니다.
왜냐하면 요소 자체가 값이라 “참조 공유”라는 문제가 없기 때문입니다.
- int[] → Clone()이면 요소 값이 그대로 복사(안전)
- Item[] → Clone()이면 요소 “참조”가 그대로 복사(공유 위험)
6) 언제 얕은 복사가 문제이고, 언제 괜찮나?
얕은 복사가 “나쁘다”가 아니라, 공유가 의도와 맞는지가 중요합니다.
얕은 복사가 위험해지는 경우
- 복사본을 수정했는데 원본도 같이 바뀌면 버그가 되는 상황
얕은 복사가 오히려 좋은 경우
- 큰 데이터를 매번 복사하면 비용이 커서, 읽기 전용으로 공유하는 게 합리적인 상황
- 내부 객체가 불변(immutable)이거나 수정되지 않는다고 보장되는 상황
'개발기록 > Computer Science' 카테고리의 다른 글
| [C# 이해하기] 값형식(Value Type)과 참조 형식(Reference Type) (0) | 2026.01.03 |
|---|---|
| 컴퓨터 구조 (0) | 2025.12.09 |
| [C언어] 데이터 입력 (0) | 2025.12.09 |
| [C언어] 문자열 (0) | 2025.11.30 |
| [C언어] 정수 자료형과 실수 자료형 (0) | 2025.11.29 |