C++ 고급 문법 (13) — 스마트 포인터(Smart Pointer)
new로 만든 객체는 누군가 정확히 한 번 delete해야 한다. 함수 중간에 return이나 예외가 끼면 해제가 빠지고, 두 곳에서 해제하면 이중 해제가 된다. 스마트 포인터(smart pointer)는 이 "누가 언제 해제하는가"를 타입으로…
new로 만든 객체는 누군가 정확히 한 번 delete해야 한다. 함수 중간에 return이나 예외가 끼면 해제가 빠지고, 두 곳에서 해제하면 이중 해제가 된다. 스마트 포인터(smart pointer)는 이 "누가 언제 해제하는가"를 타입으로…
로그를 백만 줄 쓰는 코드에서 std::endl을 '\n'으로 바꾸기만 했는데 실행 시간이 수십 배 줄어든다. std::endl은 줄바꿈과 함께 버퍼를 비우는(flush) 조작자이고, flush는 매번 시스템 호출로 이어진다. std::cout에는 이 밖에도 C stdio와의…
벡터 덧셈을 add(a, b) 대신 a + b로 쓰고, 사용자 타입을 std::set에 넣으려면 연산자 오버로딩(operator overloading)이 필요하다. 연산자는 이름이 operator+인 함수일 뿐이지만, 멤버로 둘지 비멤버로 둘지, 무엇을 반환할지에 따라 대칭성·성능·의미가…
qsort, signal, pthread_create처럼 C 라이브러리는 동작을 바꿀 때 함수의 주소를 받는다. C++에서도 C 라이브러리와 연동하거나, 명령 이름과 처리 함수를 표로 묶거나, 플러그인 진입점을 받을 때 함수 포인터(function pointer)를 그대로 쓴다.…
복사 생성자를 따로 쓰지 않아도 Buffer b = a;는 컴파일된다. 컴파일러가 멤버를 하나씩 복사하는 기본 복사 생성자를 만들어주기 때문이다. 멤버가 값 타입이면 이것으로 충분하지만, 생 포인터로 자원을 소유하고 있으면 포인터…
함수 인자를 const T&로 받도록 바꿨더니 그 안에서 부르던 getter가 전부 컴파일 에러를 낸다. getter에 const를 붙이지 않았기 때문이다. 멤버 함수 뒤의 const는 "이 함수는 객체 상태를 바꾸지 않는다"는 약속이다.…
생성자는 객체를 사용 가능한 상태로 만드는 함수인데, 본문 {}이 실행되기 전에 이미 많은 일이 끝나 있다. 기반 클래스와 멤버는 정해진 순서로 먼저 생성되고, 초기화 리스트에 쓴 순서는 그 순서를 바꾸지…
C 스타일 캐스트 (T)x는 무엇이든 통과시킨다. const를 떼는 것도, 전혀 관계없는 타입의 포인터로 바꾸는 것도 경고 없이 한 줄에 끝난다. 다중 상속이나 불완전 타입이 섞이면 같은 문법이 상황에 따라 다른…
const char* p = make_path().c_str(); 한 줄은 컴파일러 경고 없이 통과하고, 대개 출력도 멀쩡하게 나온다. 하지만 p가 가리키는 메모리는 이미 해제된 상태다. make_path()가 반환한 std::string은 이름 없는 임시 객체(temporary object)이고,…
std::sort에 비교 함수를 넘기는 방법은 여러 가지다. 함수 포인터, operator()를 가진 클래스, 람다(lambda), std::function 중 무엇을 넘기든 결과는 같다. 그런데 천만 개를 정렬해 보면 실행 시간은 2배 가까이 벌어진다. 차이는…