32. ref 반환·ref 지역 변수·ref readonly 와 인플레이스 수정
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 주제: ref 반환(ref return) · ref 지역 변수(ref local) · ref readonly 와 인플레이스 수정
//
// 게임 서버에서 대량의 값 형식(struct) 배열(엔티티 컴포넌트 등)을 다룰 때, 복사 없이
// 원소를 제자리에서 수정하려면 ref 반환/ref 지역 변수를 쓴다. 이 코드가 어떻게
// 동작하는지(원본 배열이 바뀌는지, 복사가 일어나는지)를 예측·설명하는 문제다.
//
// 과제:
// 1) Main 의 각 출력이 무엇이 될지 순서대로 예측하라.
// 2) `ref var slot = ref pool.GetRef(1);` 로 얻은 slot 을 수정하면 왜 원본 배열이
// 바뀌는지, `var copy = pool.GetRef(1);` (ref 없이 받기)는 왜 안 바뀌는지 설명하라.
// 3) ref return 이 가리키는 저장 위치의 수명(예: 지역 배열 vs 필드 배열)과, 컴파일러가
// 막는 위험한 반환(스택 이스케이프)을 설명하라.
// 내부 동작 설명은 answer.md 에서 다룬다.
using System;
public struct Entity
{
public int Hp;
public int Mana;
public override string ToString() => $"(Hp={Hp},Mana={Mana})";
}
public sealed class EntityPool
{
private readonly Entity[] _items;
public EntityPool(int n) { _items = new Entity[n]; }
// 배열 원소의 저장 위치 자체를 참조로 돌려준다(복사 아님)
public ref Entity GetRef(int i) => ref _items[i];
// 읽기 전용 참조(수정 불가, 복사 회피)
public ref readonly Entity Peek(int i) => ref _items[i];
public int Count => _items.Length;
}
public static class Program
{
public static void Main()
{
var pool = new EntityPool(3);
// (1) ref 지역 변수로 받아 제자리 수정
ref Entity slot = ref pool.GetRef(1);
slot.Hp = 100;
slot.Mana = 50;
Console.WriteLine($"A {pool.GetRef(1)}"); // 원본 반영?
// (2) ref 없이(값으로) 받은 뒤 수정하면 원본 배열은?
Entity copy = pool.GetRef(1);
copy.Hp = -999;
Console.WriteLine($"B pool={pool.GetRef(1)} copy={copy}");
// (3) ref 지역 변수를 다른 원소로 재바인딩
slot = ref pool.GetRef(2);
slot.Hp = 7;
Console.WriteLine($"C idx1={pool.GetRef(1)} idx2={pool.GetRef(2)}");
// (4) ref readonly 로 읽기(복사 없이 읽기)
ref readonly Entity r = ref pool.Peek(1);
Console.WriteLine($"D {r}");
}
} 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.