주간 팁 #123: absl::optional과 std::unique_ptr

원래 게시일: 2016-09-06
작성자: Alexey Sokolov (sokolov@google.com)
Etienne Dechamps (edechamps@google.com)


값을 저장하는 방법

이 팁에서는 값을 저장하는 여러 가지 방법을 다룹니다. 여기서는 클래스 멤버 변수를 예로 들지만, 아래의 많은 점은 지역 변수에도 적용됩니다.

CPP
#include <memory>
#include "absl/types/optional.h"
#include ".../bar.h"

class Foo {
  ...
 private:
  Bar val_;
  absl::optional<Bar> opt_;
  std::unique_ptr<Bar> ptr_;
};

1. 일반 객체로 저장

val_은 가장 단순한 방식입니다.

  • Foo의 생성자에서 초기화되고, 소멸자에서 해제됩니다.
  • Bar에 기본 생성자가 있으면 명시적으로 초기화하지 않아도 됩니다.

장점:

  • 안전성: val_은 항상 유효하며 null이 될 수 없습니다. 이는 잠재적인 버그를 제거합니다.

단점:

  1. val_의 수명은 Foo 객체의 수명에 고정됩니다.
    • 교체 가능성: Bar가 이동(이사) 또는 교체 연산을 지원한다면, 기존의 참조는 여전히 유효하지만 내용은 변경할 수 있습니다.
  2. Bar 생성자에 전달할 인수는 반드시 Foo 생성자의 초기화 리스트에서 계산되어야 합니다. 복잡한 표현식이 필요한 경우 어렵습니다.

2. absl::optional<Bar>로 저장

absl::optional은 일반 객체와 std::unique_ptr의 중간 수준의 유연성을 제공합니다.

  • 객체는 Foo 내부에 저장되지만 비어 있을 수 있습니다.
  • 필요 시 opt_ = ... 또는 opt_.emplace(...)로 값을 할당할 수 있습니다.

주의사항:

  1. 비어 있는 absl::optional도 메모리를 사용합니다. (할당된 것과 동일한 크기)
  2. 객체가 언제 생성되고 소멸되는지 명확하지 않을 수 있습니다.
  3. 비어 있는 상태에서 접근하면 문제가 발생할 수 있습니다.

3. std::unique_ptr<Bar>로 저장

가장 유연한 방법입니다.

  • 객체는 Foo 외부에 저장되며, std::unique_ptr이 비어 있을 수 있습니다.
  • 객체의 소유권을 이전하거나, 다른 곳에서 소유권을 받을 수 있습니다.

장점:

  1. 소유권 이전 및 이동 가능.
  2. 객체가 동적으로 생성되므로, 더 많은 제어가 가능.

단점:

  1. 복잡성 증가:
    • 독자가 내부 구조를 이해하는 데 시간이 걸릴 수 있습니다.
    • 객체 생성 및 소멸 시점이 덜 명확합니다.
  2. CPU 캐시 비효율성:
    • 추가 간접 참조로 인해 힙 할당이 발생하고 CPU 캐시 친화도가 낮아집니다.
  3. 복사 불가:
    • std::unique_ptr<Bar>는 복사할 수 없으므로 Foo도 복사할 수 없습니다.

결론

  • 가능하면 단순한 방식을 사용하세요.
    • 일반 객체를 우선 사용.
    • 필요하면 absl::optional을 시도.
    • 마지막으로 std::unique_ptr을 사용.

비교표

Barabsl::optional<Bar>std::unique_ptr<Bar>
지연 초기화 지원✓✓
항상 안전한 접근✓
소유권 이전 지원✓
Bar의 하위 클래스 저장✓
이동 가능Bar가 이동 가능할 경우Bar가 이동 가능할 경우✓
복사 가능Bar가 복사 가능할 경우Bar가 복사 가능할 경우
CPU 캐시 친화적✓✓
힙 할당 없음✓✓
메모리 사용량sizeof(Bar)sizeof(Bar) + sizeof(bool)sizeof(Bar*) (null일 때)
객체 수명포함하는 스코프와 동일포함하는 스코프 내 제한제한 없음
f(Bar*) 호출f(&val_)f(&opt_.value()) 또는 f(&*opt_)f(ptr_.get()) 또는 f(&*ptr_)
값 제거 방법N/Aopt_.reset(); 또는 opt_ = absl::nullopt;ptr_.reset(); 또는 ptr_ = nullptr;

라이선스

작성자: Jaehun Ryu

링크: https://jaehun.me/posts/abseil-tip-123-absloptional%EA%B3%BC-stdunique_ptr/

라이선스: CC BY 4.0

이 저작물은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다. 출처를 밝히면 상업적 목적을 포함해 자유롭게 이용 가능합니다.

댓글