본문 바로가기

Effective Modern C++30

std::unique_ptr std::unique_ptr는 항상 자신이 가리키는 객체를 소유한다. std::unique_ptr를 이동시 소유권이 원본 포인터에서 대상 포인터로 옮겨진다. std::unique_ptr의 복사는 허용되지 않는다. 만약 복사가 가능하다면 두개의 std::unique_ptr가 같은 자원을 가리키며 두 포인터 모두 그 자원을 소유하고있다는 얘기가 된다. 그렇기 때문에 std::unique_ptr은 이동 전용(move-only) 형식이며 소멸시 자신이 가리키는 자원을 파괴한다. 기본적으로 파괴는 std::unique_ptr안에 있는 생포인터에 delete를 적용함으로써 수행된다. std::unique_ptr은 Hierachy 구조에서 객체를 생성하는 팩터리 함수의 반환형식으로 쓰기에 적합하다. hierachy .. 2020. 7. 12.
특수 멤버 함수들의 자동 작성 조건을 숙지하라 C++의 공식 어법에서는 특수 멤버 함수(special member function)이 있다. 세세한 조건들이 필요하긴 하지만 C++98에서는 기본 생성자, 소멸자, 복사 생성자, 복사 배정 연산자가 있다. 이 함수들은 꼭 필요한 경우에만, 즉 이 함수들이 클래스에 명시적으로 선언되어 있지는 않지만 이 함수들을 사용하는 클라이언트 코드가 존재할 때에만 작성된다. 기본 생성자는 클래스에 생성자가 하나도 선언되어 있지 않을 때 작성된다. 작성된 특수 멤버 함수들은 암묵적으로 public 이며 inline이며, 가상 소멸자가 있는 base class를 상속하는 파생 클래스의 소멸자를 제외하고는 nonvirtual이다. 가상 소멸자가 있는 base class를 상속하는 경우 파생 클래스의 소멸자는 virtual.. 2020. 7. 10.
const 멤버 함수를 스레드에 안전하게 작성하라 다항식의 근을 구하는 등 계산 비용이 큰 함수들은 꼭 필요할 때에만 계산하는 것이 바람직하다. 또한 중복해서 계산하는 것은 피해야 하며, 필요한 때만 근을 계산해서 캐시에 저장하고 그렇지 않을 때에는 캐시에 있는 값을 돌려주도록 함수를 구현하는 것이 좋다. class Polynomial{ public: using RootsType = std::vector; RootsType roots() const { if (!rootsAreValid){// 캐시가 유효하지 않으면 근들을 계산해서 rootVals에 저장 ... rootsAreValid = true; } return rootVals; } private: mutable bool rootsAreValid{ false }; mutable RootsType ro.. 2020. 7. 9.
가능하면 항상 constexpr을 사용하라 constexpr을 객체에 적용했을 때에는 const의 강화 버전처럼 작용하지만 함수에 적용했을때에는 다른 의미로 작용한다. constexpr은 단지 상수일 뿐만 아니라 컴파일 시점에서 알려진다는 점을 나타낸다. 컴파일 시점에서 알려지는 값들은 읽기 전용 메모리에 배치될 수 있다. 즉 상수이자 컴파일 시점에서 알려진 정수 값을 C++에서 정수 상수 표현식(const expression)이 요구되는 문맥에서 사용할 수 있다는 것이다. 배열 크기나 정수 템플릿 인수, 열거자 값 등이 그런 문맥에 해당한다. 그런 변수를 constexpr로 선언하면 컴파일러는 그것이 컴파일 시점 상수임을 보장해 주게 된다. int sz; constexpr auto arrSize1 = sz;// 오류! sz의 값을 컴파일 시점에.. 2020. 7. 8.
예외를 방출하지 않을 함수는 noexpect로 함수를 noexcept로 선언할 것인지 여부는 인터페이스 설계상 문제이다. 즉, 함수 호출자는 noexcept 여부에 의존할 수 있다는 것을 뜻한다. 예외를 방출하지 않음이 확실한 함수를 선언할 때 noexcept를 사용하지 않는 것은 인터페이스 명세가 허술함을 의미한다. 예외를 받게 되는 일이 없음을 약속하기 위한 표현법이다. int f(int x) throw();// C++98 버전 int f(int x) noexcept;// C++11 버전 실행 시점에서 예외가 f 바깥으로 나가게 되면 f의 에외 명세에 위반된다. C++98에서는 예외 명세가 위반되면 호출 스택이 f를 호출한 시점에 도달할 때까지 풀리며(unwind), 그 지점에서 몇 가지 동작이 취해진 후 종료된다(terminate). C++11.. 2020. 7. 7.
iterator보다는 const_iterator를 const_iterator는 const를 가리키는 포인터의 STL 버전이다. 반복자가 가리키는 것을 수정할 필요가 없을때에는 항상 const_iterator를 사용하는 것이 바람직하다. C++98까지는 삽입, 삭제 위치를 iterator로만 지정할 수 있었다. 왜곡된 방법을 사용해서라도 const_iterator를 얻어도 정작 삽입, 삭제에 사용할 수 없기 때문에 사용할 수가 없었다. 하지만 C++11부터는 컨테이너 멤버함수로 cbegin과 cend가 추가되었고, 이는 const_iterator를 돌려준다. C++11에서 const_iterator를 사용하는 방법은 다음과 같다. std::vector values; ... auto it = std::find(values.cbegin(), values.ce.. 2020. 7. 6.