2025/06 34

Effective Modern C++ #24 보편 참조와 오른값 참조(r-value ref)를 구별하라.

24. 보편 참조와 오른값 참조(r-value ref)를 구별하라.보편참조는 추상적이다. ( 선언 시 l-value, r-value 로 나뉘지 않음 ) 일반적으로 (템플릿)T 형식에 대한 r-value reference 선언 시, T&& 표기를 사용한다.하지만 반대로 코드에서 T&& 를 발견했을 때 이를 r-value reference 라고 단언할 수 없다. 다양한 예시)void f(Widget && param); // r-value refWidget&& var1 = Widget(); // r-value refauto&& var2 = var1; // r-value ref 아님templatevoid f(std::vector&& param); // r-value reftemplatevoid f(T&& par..

dev/C++ 2025.06.22

Effective Modern C++ #23 std::move와 std::forward 를 숙지하라.

오른값 참조(r-value reference), 이동 의미론 (move semantics), 완벽 전달 (Perfect Forwarding)move semantic : 유효 문맥에서 비싼 복사 연산을 덜 비싼 이동 연산으로 대체할 수 있음perfect forwarding : 함수 인자 전달 시, 대상 함수가 전달 함수로부터 받은 것과 동일한 인자를 받게 함r-value reference 라는 언어 매커니즘으로 인해 위 두개의 기능이 묶여서 사용된다.이 기능들은 직관적이지만 그리 간단하지는 않다.예상치 못한 여러 요소가 존재한다.std::move 는 모든 것을 이동 시키지 않고, perfect forwarding 은 완벽하지 않다.이동 연산이 복사 연산보다 항상 싸지 않고, 싸더라도 기대한 만큼 싸지 않을..

dev/C++ 2025.06.21

Effective Modern C++ #22 Pimpl 관용구를 사용할 때에는 특수 멤버 함수들을 구현 파일에서 정의하라

22. Pimpl 관용구를 사용할 때에는 특수 멤버 함수들을 구현 파일에서 정의하라Pimpl 은 Pointer to implementation idiom 이라고 불린다.클래스의 자료 멤버를 구현 클래스(or 구조체)를 가리키는 포인터로 대체하는 방식이다.이 때 기존의 자료 멤버는 구현 클래스로 옮기고 포인터로 접근한다. 클래스의 자료 멤버를 header에서 직접 구현하는 경우 아래와 같은 단점이 있다.(*클라이언트는 header 파일을 사용하는 cpp 코드)클라이언트의 컴파일 시간 증가ex) 하나의 cpp 파일에서 여러개의 header 를 include 함이 때 include 한 header 에, 여러 개의 header 가 또 존재하는 경우 컴파일 시간 증가함클라이언트가 header 내용에 의존하게 되어..

dev/C++ 2025.06.21

Effective Modern C++ #21 new를 직접 사용하는 것보다 std::make_unique와 std::make_shared 를 선호하라

21. new를 직접 사용하는 것보다 std::make_unique와 std::make_shared 를 선호하라std::make_shared 는 C++11 이상부터 사용 가능하며, std::make_unqiue 는 C++14 이상부터 사용 가능하다.하지만 기본적 버전 (배열 아닌 객체)는 구현이 어렵지 않다.templatestd::unique_ptr make_unique(Ts&... params) { return std::unique_ptr(new T(std::forward(params)...));} 객체의 생성자로 매개변수를 완벽 전달하고, 생성된 raw pointer 로 std::unique_ptr 가 생성된다.주의해야할 점은 이를 std namespace 에 넣으면, 추후 버전 업데이트 시 C++1..

dev/C++ 2025.06.20

Effective Modern C++ #20 std::shared_ptr 처럼 작동하되, 대상을 잃을 수도 있는 포인터가 필요하면 std::weark_ptr 를 사용하라

20. std::shared_ptr 처럼 작동하되, 대상을 잃을 수도 있는 포인터가 필요하면 std::weark_ptr 를 사용하라std::shared_ptr 처럼 동작하지만, 가리키는 객체의 소유권 공유에는 참여하지 않는 것이 편리한 경우가 존재한다.객체의 참조 횟수의 증감에는 영향을 주지 않는 것이다. std::shared_ptr 에서는 객체가 파괴되려면 가리키는 std::shared_ptr 의 참조 횟수가 0이 되면 된다.또한 자신이 가리키는 대상이 파괴되었다면, std::shared_ptr 는 이미 해당 대상을 가리키지 않고 있을 것이다. 하지만 이 새로운 포인터 std::weak_ptr의 경우, 사용하기 위해서 “자신이 가리키는 대상이 이미 파괴되었을 수 있는 문제” 가 존재한다.std::wea..

dev/C++ 2025.06.17

Effective Modern C++ #19 소유권 공유 자원의 관리에는 std::shared_ptr 를 사용하라

19. 소유권 공유 자원의 관리에는 std::shared_ptr 를 사용하라std::shared_ptr 는 공유된 소유권에 의해 관리된다.이 의미는 객체를 소유하지 않는다는 것이다. std::shared_ptr 는 두가지 장점이 존재한다.자동으로 자원을 관리하는 garbage collection 와 유사한 특징파괴 시점을 예측할 수 있다는 점에서 소멸자의 특징위 장점대로 공유 포인터가 가리키는 객체의 수명에 대해서는 신경 쓸 필요가 없다. (자동으로 자원 관리됨)하지만 객체의 파괴 시점은 알 수 있다.std::shared_ptr 에서 객체의 파괴 시점은 reference count (참조 횟수)로 알 수 있다.이는 하나의 객체(자원)을 가리키는 std::shared_ptr 의 개수이다. std::shar..

dev/C++ 2025.06.16

Effective Modern C++ #18 소유권 독점 자원의 관리에는 std::unique_ptr 를 사용하라

Smart Pointerraw pointer는 아래와 같은 이유 때문에 좋아할 수가 없다.선언만으로는 객체를 가리키는지 배열을 가리키는지 알 수 없음포인터 사용이 완료된 뒤, 가리키는 대상을 직접 파괴해야하는지 알 수 없음 (소유 여부 모름)가리키는 대상을 직접 파괴해야한다는 것을 알아도, 어떻게 파괴하는지 모름delete 로 파괴해야함을 알아도, 1번 이유로 delete, delete[] 어떤 것 사용해야하는지 모름포인터가 가리키는 대상 소유 여부를 알고 파괴법도 알아도, 모든 경로에서 1번만 파괴되는지 보장하기 어려움포인터가 가리키는 대상을 잃었는지 아는법 없음 (가리키는 대상이 유효한지, 파괴되었는지 모름)smart pointer (raw pointer의 wrapper) 를 사용해서 이러한 문제를 ..

dev/C++ 2025.06.14

Effective Modern C++ #17 특수 멤버 함수들의 자동 작성 조건을 숙지하라.

17. 특수 멤버 함수들의 자동 작성 조건을 숙지하라.특수 멤버 함수는 C++ 컴파일러가 직접 작성하는 멤버함수다.특수 멤버 함수의 종류는 아래와 같다. (C++98 에서도 동일)기본생성자 (Default Constructor)소멸자 (Destructor)복사 생성자 (Copy Constructor)복사 배정 연산자 (Copy Assignment Operator)특수 멤버 함수는 클래스에 명시적으로 정의되어 있지 않아도, 이 함수를 사용하는 클라이언트 코드가 존재할 때 컴파일러에 의해 자동 작성된다.특수 멤버 함수는 public, inline 이며 웬만하면 non-virtual 이다.예외로 base 클래스의 가상 소멸자를 상속하는 derived 클래스 소멸자만 디폴트로 virtual 이다. C++11 에..

dev/C++ 2025.06.14

Effective Modern C++ #16 const 멤버 함수를 스레드에 안전하게 작성하라.

16. const 멤버 함수를 스레드에 안전하게 작성하라.const 멤버 함수는 읽기 연산을 수행한다.따라서 일반적으로 읽기 역할을 하는 함수에 대해서는 const 가 붙는다.class Polynomial { public: std::vector roots() const;};const 멤버 함수는 내부에서 객체의 값이 변경되지 않는다. 하지만 예외적으로 일부 객체의 값을 변경해야하는 경우가 존재한다.대표적 예시로 getter 멤버 함수이나, 캐시를 활용하는 경우가 그렇다.(필요할 때만 계산하기 위해 캐시 사용) class Polynormial { public: std::vector roots() const { if (!rootsAreValid) { ..

dev/C++ 2025.06.14

Effective Modern C++ #15 가능하면 항상 constexpr 를 사용하라.

15. 가능하면 항상 constexpr 를 사용하라.constexpr는 C++11 에서 가장 헷갈리는 단어이다.객체에 적용할 때는 const 강화버전 같지만, 함수에 적용할 때는 다른 의미로 작용한다. constexpr 는 그 값이 상수이며 컴파일 시점에서 알려진다는 것을 나타낸다. constexpr 객체의 값은 const 이며 컴파일 시점에 알려진다.컴파일 시점에 알려지는 값은 읽기 전용 메모리에 배치될 수 있다.따라서 constexpr 객체는 C++ 정수 상수 표현식 (integral constant expression) 이 요구되는 문맥에서 사용할 수 있다.예시로는 배열 크기, 정수 템플릿 인수 (std::array 크기), enum 값, alignment 지정 등이다.#include int mai..

dev/C++ 2025.06.14