기술 노트/Google C++ Style Guide

Google C++ Style Guide(2024) - 6장 Google 특유의 테크닉(Google-Specific Magic)

anothel 2024. 11. 9. 19:00

6장 Google 특유의 테크닉(Google-Specific Magic)

Google에서는 C++ 코드를 더욱 견고하게 만들기 위한 다양한 트릭과 유틸리티를 사용하며, 일반적인 C++ 관행과는 약간 다르게 코딩하는 방식도 있다. 이러한 기술들은 코드의 안정성과 유지보수성을 높이기 위한 목적으로 사용된다.

Google이 사용하는 주요 기술과 관행

  • 유틸리티와 도구
    • Google은 코드 품질을 높이기 위해 특정 유틸리티 라이브러리와 도구들을 사용한다. 예를 들어, Google Test와 Abseil 같은 라이브러리는 코드의 테스트와 유틸리티 기능을 추가하여 코드의 안정성을 높인다.
  • 모범 사례와 일관성
    • Google은 모든 코드가 일관된 스타일과 규칙을 따르도록 함으로써, 팀의 규모와 관계없이 유지보수가 용이한 코드를 유지한다.
  • 다양한 코드 스타일 적용
    • Google은 일반적인 C++ 스타일 가이드와는 약간 다른 방식을 취하기도 한다. 예를 들어, 특정 성능 최적화 기법이나 메모리 관리를 위해 내부적으로 사용되는 패턴이나 규칙이 있을 수 있다.

이러한 Google 특유의 기술들은 주로 코드 품질과 성능을 극대화하기 위한 목적이며, Google의 코드베이스에 최적화된 방식으로 설계되어 있다.

6.1 소유권과 스마트 포인터 (Ownership and Smart Pointers)

동적으로 할당된 객체는 단일, 고정된 소유자를 두는 것이 가장 이상적이며, 소유권을 전달할 때는 스마트 포인터를 사용하는 것이 좋다. 이는 메모리 관리와 자원의 수명을 명확하게 하여 코드의 안정성을 높이는 데 기여한다.

소유권의 정의

"소유권"이란 동적으로 할당된 객체의 생애를 관리하는 개념으로, 특정 객체나 함수가 소유자가 되어 필요 없을 때 삭제를 책임진다. 소유권이 공유되는 경우도 있지만, 일반적으로 마지막 소유자가 객체를 삭제하는 역할을 맡는다. 소유권은 단독으로 유지될 수도, 코드 간에 이동할 수도 있다.

스마트 포인터의 역할

스마트 포인터는 *와 -> 연산자를 오버로딩하여 일반 포인터처럼 동작하는 클래스로, 소유권 관리를 자동화하는 데 도움을 준다.

  • std::unique_ptr
    • 객체의 단독 소유권을 표현하며, 소유자가 스코프를 벗어나면 객체가 삭제된다. 복사는 불가능하지만 이동을 통해 소유권을 전달할 수 있다.
  • std::shared_ptr
    • 객체의 공유 소유권을 표현하며, 복사가 가능하다. 모든 std::shared_ptr 인스턴스가 소멸될 때 객체가 삭제된다.

스마트 포인터 사용의 장점

  • 가독성 향상
    • 소유권을 명확하게 표현하여 코드의 의미가 더 명확해지고, 문서화되지 않아도 이해할 수 있다.
  • 자동 소유권 관리
    • 소유권을 수동으로 관리할 필요가 없어져 코드가 단순해지며, 오류 발생 가능성도 줄어든다.
  • 리소스 전달의 간결함
    • 소유권 전달은 객체 복사보다 비용이 적고 간단하여, 특히 객체 복사가 불가능한 경우 유리하다.
  • 불변 객체의 공유
    • const 객체의 경우, 복사 비용을 줄이기 위해 공유 소유권을 사용하는 것이 좋은 대안이 될 수 있다.

스마트 포인터 사용 시 주의사항

  • 포인터의 복잡한 의미
    • 포인터를 사용할 때는 소유권, 수명, 불변성 등 여러 가지 복잡한 요소를 관리해야 하므로, 가급적 단일 소유권이 가장 이상적이다.
  • 성능 과대평가
    • 값 전달 방식의 성능 비용은 종종 과대평가되는 경향이 있어, 소유권 이동이 코드 복잡성을 증가시키는 경우에는 피하는 것이 좋다.
  • 소유권 공유의 위험
    • 공유 소유권을 사용하는 것은 쉽게 시스템 설계를 복잡하게 만들 수 있으며, 특히 순환 참조가 발생할 경우 객체가 영구적으로 삭제되지 않는 문제가 발생할 수 있다.

권장 사항

  • 단독 소유권은 std::unique_ptr로 표현하고, 필요할 경우 이동 연산을 사용하여 소유권을 전달한다.
std::unique_ptr<Foo> FooFactory();
void FooConsumer(std::unique_ptr<Foo> ptr);
  • 공유 소유권은 특별한 이유가 있을 때만 사용한다. 예를 들어, 복사 비용이 높은 불변 객체일 때 std::shared_ptr<const Foo>와 같은 방식을 사용할 수 있다. 성능상의 이점이 분명한 경우에만 std::shared_ptr를 고려한다.
  • std::auto_ptr는 절대 사용하지 않는다. 대신 std::unique_ptr를 사용한다.

결론

스마트 포인터를 통해 소유권을 명확하게 관리하면 코드가 더 안전해지고 유지보수성이 높아진다. 단독 소유권은 std::unique_ptr로 명확하게 관리하며, 공유 소유권은 꼭 필요한 경우에만 std::shared_ptr를 사용하여 코드의 복잡성을 최소화하는 것이 바람직하다.

6.2 cpplint

cpplint.py는 C++ 코드에서 스타일 오류를 감지하는 도구로, Google C++ 스타일 가이드에 맞는 코드 작성에 도움을 준다. 완벽하지는 않아 오탐(false positive)과 누락(false negative)이 발생할 수 있지만, 여전히 중요한 스타일 검토 도구로 여겨진다.

cpplint 사용 방법

  • 일부 프로젝트는 cpplint.py 실행에 대한 구체적인 지침을 제공하며, 프로젝트의 툴체인에 통합된 경우가 많다.
  • 만약 프로젝트에서 cpplint.py 사용 지침이 없다면, 별도로 cpplint.py를 다운로드하여 사용할 수 있다.

cpplint.py를 통해 코드 일관성을 높이고, 스타일 오류를 사전에 감지해 코드 품질을 유지할 수 있다.


참조URL

https://google.github.io/styleguide/cppguide.html

728x90