목록분류 전체보기 (68)
INDIES
std::move, std::forward 이해하기std::move와 std::forward에 대해 가장 먼저 알아야 할 점은, 이들 함수는 실제로 어떤 동작을 수행하지 않는다는 것이다. std::move가 실제로 객체를 move시키지 않고, std::forward도 실제로 객체를 forward하지 않는다. 이들 함수는 단순히 캐스팅을 수행하는 함수(함수 템플릿)일 뿐이다. std::move는 무조건 인자로 넘어온 값을 rvalue reference로 캐스팅해주고, std::forward는 특정한 조건이 만족될 경우에만 인자로 넘어오는 값을 rvalue reference로 캐스팅해준다.std::move먼저 std::move의 동작부터 이해해보자. std::move의 동작을 간략하게 구현하면 아래와 같이 ..
pImpl idiompImpl(pointer to Implementation) idiom은 프로그램 빌드에 걸리는 시간을 줄여주기 위한 기법중 하나다. 클래스의 데이터 멤버를 구현 객체(implementation class or struct)에 옮긴 후 그걸 가리키는 포인터를 멤버로 들고 있게 만드는 것이다. 예를 들어, Widget 클래스가 다음과 같이 선언되어 있다고 하자.class Widget { public: Widget(); private: std::string name; std::vector data; Gadget g1, g2, g3; };Widget은 멤버로 std::string, std::vector, Gadget 타입을 갖고 있기 때문에 , , "Gadget.h" 세 개의 파일을 incl..
make_shared, make_uniquestd::make_shared와 std::make_unique는 각각 shared_ptr과 unique_ptr을 만들기 위해 사용되는 템플릿 함수들이다. 근데 왜인지는 몰라도 std::make_shared는 C++ 11 표준에 포함이 되어있는데 std::make_unique는 C++ 11표준에 포함이 안 돼있다. std::make_unique는 C++ 14부터 표준에 들어가는데, C++ 11 표준에서 std::make_unique를 쓰고 싶다면 아래의 간단한 코드를 이용하면 된다.template std::unique_ptr make_unique(Ts&&... params) { return std::unique_ptr(new T(std::forward(params..
std::weak_ptr의 사용std::shared_ptr처럼 동작하지만 막상 레퍼런스 카운팅은 되지 않는 포인터가 유용하게 쓰일 때가 있다. 이런 포인터를 std::weak_ptr이라고 부른다. std::weak_ptr은 역참조(dereference)도 안 되고 nullptr인지 아닌지 테스트하는 것도 안 된다. std::weak_ptr은 그 자체로 홀로 쓰이는 스마트 포인터가 아니기 때문이다. 이까지만 들으면 당최 이 놈이 어디서 유용하다는 것인지 전혀 이해가 안 될 수 있다. 하지만 std::weak_ptr은 굉장히 유용한 스마트 포인터이다. 어떤 경우에 활용될 수 있는지 하나씩 살펴보자.dangling 감지std::weak_ptr은 이미 파괴됐을 가능성이 있는 자원을 참조해야할 경우가 있을 때 해..
공유 자원 관리에는 std::shared_ptr요즘 나오는 언어들은 거의 대부분 garbage collection 기능을 갖고 있다. 반면 C++은 언어 차원에서 garbage collection을 지원해주지 않기 때문에 사용한 자원을 일일히 해제해줘야하는 어려움이 있었는데, 이런 어려움을 해결하기 위해 등장한 것이 shared_ptr이다. shared_ptr은 garbage collection처럼 여럿이 공유하는 자원을 더 이상 필요없을 때 자동으로 해제해줄 뿐만 아니라, 어느 시점에 해제되는지도 알 수 있다(garbage collection은 자원이 정확히 어느 시점에 해제되는지 알기 힘들다. 자동으로 일정 규칙에 따라 관리하다가 해제할 때가 되면 해제하기 때문에).shared_ptr의 동작 원리는 ..
포인터는 C/C++을 강력한 언어로 만들어주는 도구이면서 동시에 굉장히 다루기 까다로운 언어로 만들어주는 도구이다. 왜 포인터는 어렵고 짜증나는 개념인가? 그 이유를 대충 요약하자면 아래 6가지 정도의 항목이 나온다.포인터가 가리키는 주소의 값이 배열인지 하나의 객체인지 판별이 불가능하다.포인터가 가리키고 있는 주소의 값을 내가 다 쓰고 나서 파괴해야할지 아닐지 판단하는게 불가능하다. 즉, 포인터가 가리키는 대상을 내가 소유하고 있는지 아닌지 알 수 있는 방법이 없다.만약에 포인터가 가리키는 대상을 파괴하기로 마음먹었다고 하자. 문제는, 그걸 파괴하기 위해 어떤 방법을 써야할 지 알아낼 방법이 없다는 것이다. 모든 자원을 다 delete를 써서 제거하는 것은 아니다. release 등의 특정 함수를 호출..
special member functionC++에서 special member function이란 따로 명시하지 않아도 저절로 생성될 수 있는 멤버 함수들을 말한다. C++ 98에는 기본 생성자, 기본 파괴자, 복사 생성자, 복사 대입 연산자라는 4개의 special member function이 있었다.C++11에는 여기서 이동 생성자, 이동 대입 연산자라는 두 가지 special member function이 더 추가 되었다.class Widget { public: Widget(Widget&& rhs); Widget& operator =(Widget&& rhs); };새로운 두 special member function은 위와 같은 type signature를 갖고 있다. 이 함수들도 조건이 성립하면..
const 멤버 함수는 thread safe수학에서 다항식(polynomial)을 나타내는 클래스를 만든다고 해보자. 다항식을 나타내는 클래스니까 다항식의 근(roots)들을 구하는 함수가 있으면 굉장히 편리할 것이다. 근을 구하는 함수는 다항식 자체에는 어떤 영향을 끼치는게 아니니 이건 const 멤버 함수로 선언하자.class Polynomial { public: using RootsType = std::vector; RootsType roots() const; };다항식의 근을 계산하는 함수는 비용이 굉장히 비쌀 것이다. 근은 한 번만 계산하면 바뀌는 값이 아니므로 한 번 계산한 다음에는 값을 캐시(cache)해두고 바로바로 불러오는 방식으로 하면 성능이 훨씬 개선된다.class Polynomial..
const_iterator를 쓰자!STL에서 const_iterator는 포인터로 따지면 const T* 와 같다. 즉 iterator가 가리키는 대상을 수정하지 못함(데이터의 상수성)을 의미하는 것이다. Effective C++에서도 다룬 내용이지만 const는 많이 쓸 수록 좋다. 해당 iterator가 가리키는 대상을 꼭 수정할 필요가 없다면 const_iterator를 사용하는 편이 더 안정적인 코드가 될 것이다.C++ 98에서는 써먹을 게 못 됐다const를 쓸 수 있으면 가능한 한 많이 쓰는 게 좋다는 일반적인 원칙에도 불구하고 C++ 98에서는 const_iterator를 쓰기가 힘들었다. 사용하기도 굉장히 불편했고 기능이 제대로 구현되어 있다고 보기 힘든 상태였기 때문이다. 예제를 통해 C..
오버라이딩엔 overrideC++에서 오버라이딩은 굉장히 흔히 쓰이는 개념이다. 상속받은 클래스가 기반 클래스의 함수를 재정의하는 것을 오버라이딩이라고 하는데, 오버라이딩이 일어나기 위해선 몇 가지 조건이 필요하다.기반 클래스의 함수가 가상 함수(virtual function)이어야만 한다.기반 함수와 상속된 함수(derived function)의 이름이 반드시 같아야한다(소멸자 제외).기반 함수와 상속된 함수의 매개변수 타입도 반드시 같아야한다.기반 함수와 상속된 함수의 상수성(constness)도 반드시 같아야한다.기반 함수와 상속된 함수의 리턴 타입 및 예외 지정(exception specification)이 서로 호환되어야만 한다.굉장히 당연해보이는 조건들이다. 여기에 C++ 11에서는 한 가지 ..