3. struct 값 의미론, 박싱, 가변 구조체의 함정
난이도 상내 리뷰 · C#
해설 · C#
해설 — struct 값 의미론, 박싱, 가변 구조체의 함정
난이도: 상
답변 프레임워크: 요약 → 핵심 개념 → 단계별 내부 동작 → 흔한 오해·함정 → 면접 포인트
요약
예상 출력:
a.X=1, b.X=2
arr[0].X=11
list[0].X=20
c.X=101, boxed.X=100
h.P.X=6
b = a는 값 복사라b.IncX()가a에 영향 없음 →a.X=1, b.X=2.- 배열 원소
arr[0]은 변수(addressable) 라arr[0].IncX()가 원본을 바꿈 →11. list[0]인덱서는 복사본을 반환 →tmp를 바꿔도 리스트는 그대로 →20.boxed = c시점에 복사가 힙으로 들어감. 이후c.IncX()는 c 만 101, 박스는 100.h.P는 클래스 필드라 변수 →h.P.X=5후IncX()로6.
핵심 개념
- 값 타입 복사 의미론: struct 는 대입·인자 전달·반환 시 비트 단위 복사. 두 변수는 독립적. (class 는 참조 복사라 같은 객체를 공유.)
- "원소가 변수냐 복사냐":
- 배열
T[]: 인덱싱 결과는 변수(lvalue) →arr[i].field = v,arr[i].Mutate()가 원본을 바꾼다. - List
인덱서 :this[int]는 값을 반환(rvalue 복사).list[i].field = v는 컴파일 에러(CS1612, "반환값을 수정할 수 없음"),list[i].Mutate()는 조용히 복사본만 바꾸고 버린다(무효과). 바꾸려면var t = list[i]; t.Mutate(); list[i] = t;.
- 배열
- 박싱(boxing): 값 타입을
object/인터페이스로 변환하면 힙에 복사본(박스)이 생긴다. 언박싱((Point)boxed)도 복사를 꺼낸다. 그래서 박스와 원본은 독립적이고, 인터페이스를 통해 mutate 하면 박스만 바뀐다(원본 아님) — 가변 구조체의 대표적 혼란. - 가변 구조체 안티패턴: 위처럼 "어디서 복사가 일어나는지"가 보이지 않아 직관과 다른 결과를 낳는다. 권장은 불변(readonly) struct.
단계별 내부 동작
b = a→ 스택에 a 의 비트 복사.b.IncX()는 b 만.arr[0].IncX()→ 배열 원소는 변수. 메서드가 그 자리(원소)를 직접 mutate → 11.var tmp = list[0]→ 인덱서가 복사본 반환, tmp 에 복사.tmp.IncX()는 tmp 만 → list[0] 은 20. (list[0].IncX()를 직접 써도 동일하게 무효과;list[0].X=5는 컴파일 에러.)object boxed = c→ X=100 인 c 가 힙 박스로 복사.c.IncX()→ c.X=101.(Point)boxed는 박스(100)의 복사를 반환 → 100.h.P.X = 5→ h(참조형)의 필드 P 는 변수라 직접 수정.h.P.IncX()→ 6.
흔한 오해·함정
- "메서드를 불렀으니 바뀌었겠지": List/프로퍼티/인덱서가 반환한 struct 는 복사본일 수 있다. mutate 가 조용히 사라진다.
- 박싱 비용/누수: 값 타입을
object/비제네릭 컬렉션/인터페이스로 다루면 박싱 발생 → 힙 할당·GC 압박. 게임서버 핫패스에서IComparable/object경유 박싱을 조심(제네릭 제약where T : struct/IEquatable<T>로 회피). - 큰 struct 의 복사 비용: 값 복사가 잦으면 오히려 느리다. 큰 데이터는 class 또는
in/ref전달,readonly struct/ref struct(Span) 고려. - mutable struct + 컬렉션/프로퍼티 조합이 버그의 온상 → 불변 struct + "변경은 새 값 반환(with 식/record struct)".
면접 포인트
- 값/참조 의미론과 "어디서 복사가 일어나는가"(대입·전달·반환·인덱서·박싱).
- 배열 인덱싱은 변수, List 인덱서는 복사 반환 —
list[i].field=...가 컴파일 에러인 이유 (CS1612), 우회 패턴. - 박싱의 메커니즘·비용과 회피(제네릭/제약), 가변 구조체가 안티패턴인 이유, readonly/ref struct 활용.