스토리텔링 개발자

[Effective Modern C++] 29. 이동 연산이 없다고 가정하기 본문

Effective C++/Effective Modern C++

[Effective Modern C++] 29. 이동 연산이 없다고 가정하기

김디트 2025. 3. 24. 11:58
728x90

항목 29. 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라

 

 

 

개요
  • 이동 의미론이 의미를 가지고, 성능을 개선시킬 수 있는 것은 사실이다.
  • 하지만, 그렇지 않은 상황도 분명 존재한다.

 

 

 

이동 연산이 없다
  • 이동 의미론을 지원하지 않는 타입들이 많다
  • C++11의 표준 라이브러리는 이동을 복사보다 빠르게 구현할 수 있는 타입에 대해서만 이동 연산들을 추가했다.
    • 반대로 말하면 구현되지 않은 타입도 존재한다는 뜻이다.
  • 구현되지 않았더라도 C++11이 자동으로 이동 연산을 작성해 주니 성능 향상은 발생한다?
  • 이동 연산이 자동 생성되지 않는 경우들이 존재한다.
    • 타입에 복사 연산이나 이동 연산, 소멸자가 하나라도 있는 경우.(항목 17 참조)
    • 타입의 자료 멤버나 기반 클래스에 이동이 비활성화 되어 있는 경우.(항목 11 참조)

 

 

 

이동이 더 빠르지 않다
  • 이동을 명시적으로 지원하는 타입이라도 이득이 생각만큼 크지 않을 수 있다.
  • 예컨대 c++1 표준 라이브러리의 모든 컨테이너는 이동을 지원한다.
  • 하지만 모든 컨테이너의 이동이 저렴하다고 가정하면 안된다.
    • 컨테이너에 담긴 내용을 정말 저렴하게 이동하는 방법이 없는 컨테이너도 있고,
    • 컨테이너가 제공하는 저렴한 이동 연산이 요구하는 까다로운 조건을 만족시킬 수 없는 경우도 있다.
  • std::array
    • 원시 배열에 STL 인터페이스를 씌운 것이다.
    • 보통의 컨테이너는 요소들의 포인터를 관리하지만, std::array는 요소 자체를 관리한다.

보통의 컨테이너는 포인터를 관리한다.
std::array에 직접 저장된다.

  • std::array는 결국 이동과 복사 모두 계산 복잡도가 선형(linear)이다.
    • 결국 이동으로 얻는 성능상 이점이 아주 미미하다.
    • 컨테이너를 이동하는 것이 포인터를 복사하는 것만큼이나 저렴하다!는 주장과는 거리가 멀다.
  • std::string
    • 상수 시간 이동과 선형 시간 복사를 제공한다.
    • 이동이 복사보다 빠를 것 같지만, 반드시 그렇진 않다.
    • 작은 문자열 최적화가 적용되는 작은 문자열에는 이동이 복사보다 빠르지 않다.
      • 대체로 이동이 복사보다 빠른 것은 포인터 하나만 복사하면 되기 때문인데
      • 이 경우 그런 요령을 적용할 수 없기 때문이다.
  • 작은 문자열 최적화(small string optimization, SSO)
    • 작은 문자열(용량이 15자 이하)을 std::string 객체 안의 버퍼에 저장하고,
    • 힙에 할당한 저장소는 사용하지 않는다.
    • 짧은 문자열들이 빈번하고 통상적으로 쓰인다는 가정.

 

 

 

이동을 사용할 수 없다
  • 빠른 이동 연산을 지원하는 타입이지만, 복사가 일어나는 경우가 있다.
  • 표준 라이브러리의 일부 컨테이너 연산들은 강한 예외 안전성을 보장한다.
    • 그 보장에 의존하는 구식 C++98 코드를 C++11에서 컴파일에도 안정성을 보장하기 위해서
    • 이동 연산들이 예외를 던지지 않음이 확실한 경우에만 복사 연산을 이동 연산으로 자동 대체한다. (항목 14 참조)

 

 

 

원본 객체가 lValue이다
  • 아주 드문 경우(항목 25 참조)지만,
  • 오직 rValue만 이동 연산의 원본이 될 수 있는 경우도 있다.

 

 

 

결론
  • 이동 연산들이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 '가정'하자.
  • 일반적 코드(이를테면 템플릿)에서는 대체로 그런 가정을 하는 편이 좋다.
    • 코드에 쓰이는 모든 타입을 알 수 없기 때문이다.
  • 코드가 사용하는 구체적인 타입을 미리 알 수 있고, 그 타입들의 특징이 바뀌지 않음을 확신한다면
    • 위와 같은 가정을 굳이 할 필요가 없다.
728x90
Comments