← 문제로

30. 임시 객체의 수명과 참조 수명 연장(lifetime extension)

난이도 상
내 리뷰 · C++
해설 · C++

해설 — 임시 객체의 수명과 참조 수명 연장(lifetime extension)

난이도: 상

예측 출력

A
ctor 1
B 1
ctor 2
C 2
dtor 2
D
E ctor 3
3
dtor 3
F built
G
dtor 1

핵심 개념

  • 임시(temporary)의 기본 수명: 임시 객체는 그것이 등장한 전체 표현식(full expression) 이 끝나는 세미콜론에서 소멸한다. make(3).id 처럼 참조에 바인딩되지 않으면 그 줄 끝에서 바로 파괴된다.
  • 수명 연장(lifetime extension): 임시를 const lvalue 참조 또는 rvalue 참조직접 바인딩하면, 임시의 수명이 그 참조의 수명까지 연장된다. const Tracer& r = make(1); 의 임시는 r 이 사는 범위(여기선 main 끝)까지 산다. Tracer&& s = make(2); 도 블록 끝까지 연장된다.

단계별 내부 동작 (출력 근거)

  1. "A" 출력.
  2. const Tracer& r = make(1); → 임시 Tracer(1) 생성(ctor 1). r 에 바인딩되어 수명이 main 끝까지 연장.
  3. "B " << r.idB 1.
  4. 블록 진입, Tracer&& s = make(2);ctor 2. C 2 출력. 블록을 벗어나며 s 가 붙잡은 임시 소멸 → dtor 2.
  5. "D" 출력.
  6. std::cout << "E " << make(3).id: C++17에서 <<는 좌변이 우변보다 먼저 시퀀스된다. 그래서 "E "가 먼저 나가고(E ), 그 다음 make(3) 가 임시를 만든다(ctor 3), .id(=3) 출력(3). 이 임시는 이 전체 표현식의 끝(세미콜론)에서 소멸 → dtor 3.
  7. std::string_view sv = std::string("hello world").substr(0,5);substr 이 만든 임시 std::string은 이 줄 끝에서 소멸한다. sv이미 소멸한 문자열의 내부 버퍼를 가리키는 dangling view 가 된다 (여기서는 접근하지 않아 UB를 실행하진 않지만, 이후 sv 사용은 UB). F built 만 출력.
  8. "G" 출력, main 반환. 마지막으로 r 이 붙잡은 임시(1) 소멸 → dtor 1.

흔한 오해·함정

  • 함수를 거치면 연장되지 않는다. const T& identity(const T& t){ return t; } 에 대해 const T& r = identity(make(5)); 는 연장되지 않는다. 수명 연장은 임시를 참조에 직접 바인딩할 때만 적용된다. identity 안의 매개변수 t 는 임시를 가리키지만, 반환된 참조를 바깥 r 에 바인딩하는 것은 "임시 → 참조" 직접 바인딩이 아니다. 임시는 그 줄 끝에서 죽고 r 은 dangling.
  • 멤버 참조로는 전체 임시가 연장되지 않는다(주의 규칙). 집합체 초기화 등 특수 상황에서 멤버 참조에 임시를 바인딩하면 규칙이 미묘하다 — 일반적으로 클래스 멤버 참조는 임시 수명을 연장하지 않는다.
  • 뷰 타입(string_view, span)의 dangling: 뷰는 소유하지 않는다. rvalue(임시 컨테이너)에서 뷰를 얻으면 원본이 즉시 소멸해 dangling. std::string_view sv = get_string();(반환이 값이면) 같은 코드가 대표적 버그.
  • auto&& 와 범위 기반 for: for (auto&& x : makeVector()) 는 makeVector()의 임시가 루프 동안 연장되어 안전하다. 하지만 for (auto x : makeVector().items()) 처럼 멤버가 반환한 뷰/참조를 순회하면 임시 컨테이너는 죽어 dangling 이 될 수 있다.

면접 포인트

  • 수명 연장이 적용되는 정확한 조건(임시를 const&/&& 에 직접 바인딩)과, 함수 반환을 거치면 깨지는 이유.
  • string_view/span 이 왜 "빌려온 뷰"이며 rvalue 원본과 만나면 위험한지.
  • C++17에서 << 연산자 피연산자의 시퀀스 규칙(좌변이 우변보다 먼저)이 출력 순서에 주는 영향.