전체 글

자원 누출을 막기 위해, 생성자 안에서 자원을 획득하고 소멸자에서 그것을 해제하는 RAII 객체를 사용하자. 일반적으로 쓰이는 RAII 클래스는 tr1::shared_ptr, auto_ptr이다. tr1::shared_ptr이 복사 시의 동작이 직관적이기 때문에 더 좋다. auto_ptr은 원본 객체를 null로 만든다. 자원 관리 객체 자원이란, 사용을 일단 마치고 난 후엔 시스템에 돌려주어야 하는 모든 것을 일컫는다. 특히 동적 할당된 메모리가 있고 파일 서술자, 뮤텍스 잠금, GUI, 폰트, 브러시 등이 있다. 이러한 자원들을 관리하는데 효과적인 방법 중 하나는 자원 관리 객체를 사용하는 것이다. 투자를 모델링해 주는 클래스 라이브러리를 가지고 작업을 한다고 가정하자. 이 라이브러리는 Investm..
객체 복사 함수는 주어진 객체의 모든 데이터 멤버 및 모든 기본 클래스 부분을 빠뜨리지 말고 복사해야 한다. 클래스의 복사 함수 두 개를 구현할 때, 한쪽을 이용해서 다른 쪽을 구현하지 마라. 그 대신, 공통된 동작을 제3의 함수에다 분리해 놓고 양쪽에서 호출해라. 객체를 복사할 때 주의할 점 객체의 안쪽 부분을 캡슐화한 객체 지향 시스템 중 설계가 잘 된 것들을 보면, 복사 함수가 복사 생성자와 복사 대입 연산자 딱 둘만 있다. 이러한 복사 함수는 컴파일러가 필요에 따라 만들어내기도 한다. 컴파일러가 만든 복사함수는 기본적인 요구에 충실히 동작한다. 복사되는 객체가 갖고 있는 데이터를 빠짐없이 복사한다. 객체 복사 함수를 선언하는 것은 컴파일러가 생성하는 것보다 추가적인 동작을 하기 위해서일 것이다. ..
operator=을 구현할 때, 어떤 객체가 그 자신에 대입되는 경우를 제대로 처리해야 한다. 원본 객체와 복사대상 객체의 주소를 비교해도 되고, 문장의 순서를 적절히 조정할 수도 있으며 복사 후 맞바꾸어도 된다. 두 개 이상의 객체에 대해 동작하는 함수가 있다면, 이 함수에 넘겨지는 객체들이 같은 객체인 경우에 정확하게 동작하게 해라. operator= 자기대입 처리 자기대입이란, 어떤 객체가 자기 자신에 대해 대입 연산자를 적용하는 것을 말한다. class Widget { ... }; Widget w; ... w = w; // 자기대입 이 코드는 문제가 없는 적법한 코드이다. 다음과 같은 상황에 많이 발생한다. a[i] = a[j]; // i==j라면 자기대입 *px = *py; // 가리키는 대상이..
대입 연산자는 *this의 참조자를 반환하도록 만들어라 대입 연산자는 *this의 참조자를 반환 C++의 대입 연산은 여러 개가 사슬처럼 엮일 수 있다. int x, y, z; x = y = z = 15; // 사슬처럼 이어짐 대입 연산이 가진 특성 중 하나는 우측 연관 연산이라는 점이다. 즉, 위의 대입 연산 사슬은 다음과 같이 분석된다. x = (y = (z = 15)); 15가 z에 대입되고, 그 대입 연산의 결과가 y에 대입된 후, y에 대한 대입 연산의 결과가 x에 대입된다. 이렇게 대입 연산이 사슬처럼 엮이려면 대입 연산자가 좌변 인자에 대한 참조자를 반환하도록 구현되어 있을 것이다. 이런 구현은 관례인데, 클래스의 대입 연산자를 구현할 때는 이 점을 지켜주는 것이 좋다. class Widge..
소멸자에서는 예외가 빠져나가면 안 된다. 만약 소멸자 안에서 호출된 함수가 예외를 던질 가능성이 있다면, 어떤 예외이든지 소멸자에서 모두 처리해야 한다. 어떤 클래스의 연산이 진행되다가 던진 예외에 대해 사용자가 반응해야 할 필요가 있다면, 해당 연산을 제공하는 함수는 반드시 소멸자가 아니어야 한다. 예외가 소멸자를 떠나지 않게 하자 소멸자로부터 예외가 터져 나가는 경우를 C++ 언어에서 막는 것은 아니지만, 실제 상황을 보면 확실히 막아야 하긴 하다. class Widget { public: ... ~Widget () { ... } // 이 함수에서 예외가 발생한다고 가정 }; void doSomething() { std::vector v; ... } // v 자동 소멸 vector 타입의 객체 v는 ..
생성자 혹은 소멸자 안에서 가상 함수를 호출하지 마라. 가상 함수라고 해도, 지금 실행 중인 생성자나 소멸자에 해당되는 클래스의 파생 클래스 쪽으로 내려가지 않는다. 객체 생성 및 소멸 중 가상 함수 금지 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하면 안된다. class Transaction { // 기본 클래스 public: Transaction(); virtual void logTransaction() const = 0; // 순수 가상함수(로깅) ... }; Transaction::Transaction() // 기본 클래스 생성자 { ... logTransaction(); } class BuyTransaction: public Transaction { // Transaction의 파생..
다형성을 가진 기본 클래스에는 반드시 가상 소멸자를 선언해야 한다. 어떤 클래스가 가상 함수를 하나라도 갖고 있으면 이 클래스의 소멸자도 가상 소멸자이어야 한다. 기본 클래스로 설계되지 않았거나 다형성을 갖도록 설계되지 않은 클래스에는 가상 소멸자를 선언하지 말아야 한다. 다형성과 가상 소멸자 다형성을 갖는 클래스를 사용하는 상황을 가정해 보자. 시간 기록을 유지하는 클래스를 제작할 것인데 기본 클래스를 만들고 용도에 따라 파생시키는 구조를 설계한 상황이다. class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); ... }; class AtomicClocK: public TimeKeeper { ... }; class WaterClocK: public TimeK..
hvv_an
이미난