16. readonly struct · in 매개변수 · 방어적 복사(defensive copy)

난이도 상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 주제: readonly struct · in 매개변수 · 방어적 복사(defensive copy).
//
// 가변(비 readonly) 구조체의 "비 readonly 메서드"를 readonly 컨텍스트(readonly 필드,
// in 매개변수, ref readonly)에서 호출하면, 컴파일러는 그 메서드가 상태를 바꿀 수도
// 있다고 보고 호출 전에 구조체를 "방어적으로 복사"한 뒤 복사본에서 메서드를 실행한다.
//
// 과제:
//   1) 이 프로그램의 정확한 표준출력을 예측하라(세 줄 모두).
//   2) (1)(2) 의 결과가 (3) 의 직접 호출과 왜 다른지 — 방어적 복사가 언제, 왜 끼어드는지
//      내부 동작으로 설명하라.
//   3) 이 방어적 복사가 정확성(변경이 사라짐)과 성능(숨은 복사 비용) 양쪽에
//      어떤 문제를 일으키는지, 그리고 어떻게 제거하는지 설명하라.

using System;

struct Counter                 // 가변 구조체(비 readonly)
{
    public int Value;
    public int Next()          // 비 readonly 메서드: 상태를 바꾼다
    {
        Value++;
        return Value;
    }
}

class Program
{
    static readonly Counter s_counter = new Counter { Value = 10 };

    static int CallNext(in Counter c) => c.Next();   // in: 읽기 전용 참조

    static void Main()
    {
        // (1) readonly 필드를 통해 비readonly 메서드 호출
        int a = s_counter.Next();
        int b = s_counter.Next();
        Console.WriteLine($"a={a} b={b} field={s_counter.Value}");

        // (2) in 매개변수를 통해 비readonly 메서드 호출
        Counter local = new Counter { Value = 100 };
        int n1 = CallNext(in local);
        int n2 = CallNext(in local);
        Console.WriteLine($"n1={n1} n2={n2} local={local.Value}");

        // (3) 평범한 지역 변수에서 직접 호출(복사 없음)
        Counter direct = new Counter { Value = 0 };
        int d1 = direct.Next();
        int d2 = direct.Next();
        Console.WriteLine($"d1={d1} d2={d2} direct={direct.Value}");
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.