Object Oriented Programming(C++)/Effective C++38 Effective C++ | 항목 14 자원 관리 클래스의 복사 동작을 고찰하자 항목 14 자원 관리 클래스의 복사 동작을 고찰하자14.1 RAII 클래스의 복사 동작 자원 관리 클래스를 스스로 만들어야 하는 경우가 있다. 예를 들어, Mutex 타입의 뮤텍스 객체로 C API를 사용하고 있다고 가정해보자. RAII 법칙에 따라 이전에 걸어 놓은 뮤텍스 잠금을 풀어주는 Lock 클래스는 다음과 같이 정의할 수 있다.void lock(Mutex* pm); /* pm이 가리키는 뮤텍스의 잠금을 설정하는 C API 함수입니다. */void unlock(Mutex* pm); /* pm이 가리키는 뮤텍스의 잠금을 해제하는 C API 함수입니다. */class Lock {public: explicit Lock(Mutex* pm) : mutexPtr(pm) { lock(mutexPtr); /*.. 2022. 1. 24. Effective C++ | 항목 13 자원은 객체로 관리하자 항목 13 자원은 객체로 관리하자13.1 자원 관리 클래스 투자를 모델링해주는 클래스 라이브러리에 Investment라는 최상위 클래스가 있고 이것을 기본으로 다양한 투자 클래스가 파생되어 있다고 가정해보자. 이 라이브러리는 Investment에서 파생된 클래스의 객체를 사용자가 얻어내는 용도로 팩토리 함수(factory function)를 쓰도록 만들어져 있다.class Investment { ... }; /* 여러 형태의 투자를 모델링한 최상위 클래스 Investment */Investment* createInvestment(); /* Investment 클래스 계통의 객체를 동적 할당하고 그 포인터를 반환하는 팩토리 함수 */ createInvestment 함수를 통해 얻은 객체를 사용할 일이 없.. 2022. 1. 23. Effective C++ | 항목 12 객체의 모든 부분을 빠짐없이 복사하자 항목 12 객체의 모든 부분을 빠짐없이 복사하자 12.1 사용자가 선언한 복사 함수 객체의 안쪽 부분을 캡슐화한 객체 지향 시스템을 잘 보면 객체를 복사하는 함수가 딱 둘만 있을 것을 알 수 있다. 복사 생성자와 복사 대입 연산자라고 이 둘을 통틀어 복사 함수(copy function)라고 부른다. 객체 복사 함수를 여러분이 선언하면 이에 대해 컴파일러는 썩 반기는 분위기가 아니라는 듯, 여러분이 구현한 복사 함수가 잘못되었을 경우에도 입을 다물어 버린다. 고객을 나타내는 클래스가 하나 있다고 가정해보자. 이 클래스의 복사 함수는 호출될 때마다 로그를 남기도록 작성되었다. void logCall(const std::string& log); class Customer { /* 고객을 나타내는 클래스입니다... 2022. 1. 12. Effective C++ | 항목 11 operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 항목 11 operator=에서는 자기 대입에 대한 처리가 빠지지 않도록 하자 자기 대입(self assignment)이란 어떤 객체가 자기 자신에 대해 대입 연산자를 적용하는 것을 말한다. class Widget { ... }; Widget w; w = w; /* 아주 적법한 코드입니다. */ a[i] = a[j]; /* i와 j가 같은 값이면 자기 대입됩니다. */ *px = *py; /* px와 py가 가리키는 대상이 같으면 자기 대입됩니다.*/ 이러한 자기 대입이 생기는 이유는 여러 곳에서 하나의 객체를 참조하는 상태, 다시 말해 중복 참조(ailasing) 때문이다. 같은 타입으로 만들어진 객체 여러 개를 참조자 혹은 포인터로 물어 놓고 동작하는 코드를 작성할 때는 같은 객체가 사용될 가능성을 .. 2022. 1. 12. Effective C++ | 항목 10 대입 연산자는 *this의 참조자를 반환하게 하자 항목 10 대입 연산자는 *this의 참조자를 반환하게 하자 10.1 대입 연산자와 반환 타입 관례 C++의 대입 연산은 여러 개가 사슬처럼 엮일 수 있는 성질과 우측 연관(right associative) 연산이라는 재미있는 특성을 갖고 있다. int, x, y, z; x = y = z = 10; x = (y = (z = 10)); 이렇게 대입 연산이 사슬처럼 엮이려면 대입 연산자가 좌변 인자에 대한 참조자를 반환하도록 구현되어 있을 것이다. 이런 구현은 일종의 관례(convention)인데, 여러분이 나름대로 만드는 클래스에 대입 연산자가 들어간다면 이 관례를 지키는 것이 좋다. 이 규칙은 단순 대입형 연산자 말고도 모든 형태의 대입 연산자에서 지켜져야 한다. class Widget { public:.. 2022. 1. 11. Effective C++ | 항목 09 객체 생성 및 소멸 과정 중에는 가상 함수를 절대로 호출하지 말자 항목 09 객체 생성 및 소멸 중에는 가상 함수를 절대로 호출하지 말자 9.1 객체 생성 및 소멸 중 가상 함수 잘못 호출하기 주식 거래를 본떠 만든 클래스가 있다고 가정하자. 매수 주문, 매도 주문 등의 거래를 모델링하는 데 중요한 포인트는 감사(audit) 기능이 있어야 한다는 점이다. 다음과 같이 주식 거래 객체가 생성될 때마다 감사 로그에 적절한 거래 내역이 만들어지도록 해보자. class Transaction { /* 주식 부모 클래스 */ public: Transaction(); virtual void logTransaction() const = 0; /* 거래 로그를 기록하는 순수 가상 메서드입니다. */ }; class BuyTransaction : public Transaction { /.. 2022. 1. 11. Effective C++ | 항목 08 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 항목 08 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 8.1 예외를 내보내는 소멸자 소멸자에서는 예외가 발생한 조건이 어떤 조건인지에 따라 프로그램이 종료되던지 아니면 정의되지 않은 동작을 보인다. 이렇게 완전하지 못한 프로그램의 종료나 정의되지 않은 동작의 원인은 바로 예외가 터져 나오는 것을 내버려 두는 소멸자에게 있다. C++는 예외를 내보내는 소멸자를 싫어한다. ■ 8.1.1 소멸자의 예외 처리 여러분이 데이터베이스 연결을 나타내는 클래스를 쓰고 있다고 가정해보자. class DBConnection { public: ... static DBConnection create(); void close(); /* 연결을 닫습니다. 실패하면 예외를 던집니다. */ }; class DBConn { /* D.. 2021. 8. 29. Effective C++ | 항목 07 다형성을 가진 부모 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자 항목 07 다형적인 부모 클래스는 가상 소멸자를 선언하자 7.1 부모 클래스와 가상 소멸자 ■ 7.1.1 가상 소멸자의 선언 팩토리 함수(factory function) 새로 생성된 자식 클래스 객체에 대한 부모 클래스 포인터를 반환하는 함수를 말한다. 어떤 객체에 대한 포인터를 반환하는 용도로 사용한다. 팩토리 함수의 규칙 getTimeKeeper 함수에서 반환되는 객체는 힙에 있다. 객체를 사용하지 않으면 지원 누출을 막기 위해 객체를 적절히 삭제(delete)해야 한다. getTimeKeeper 함수가 반환하는 자식 클래스(AtomicClock) 객체를 부모 클래스의 포인터로 삭제한다. // 시간을 기록하는 TimeKeeper 클래스입니다. class TimeKeeper { public: TimeK.. 2021. 8. 29. Effective C++ | 항목 06 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해버리자 항목 06 컴파일러가 만든 함수가 필요 없으면 사용을 금하자 6.1 복사를 지원하지 않는 클래스 class HomeForSale { public: HomeForSale() { }; }; HomeForSale h1; HomeForSale h2; HomeForSale h3(h1);// h1을 자동으로 복사합니다. h1 = h2;// h2를 자동으로 복사합니다. 복사 생성자와 복사 대입 연산자가 저절로 만들어지는 것을 막기 위해 private 멤버로 선언한다. 컴파일러는 디폴트 버전을 생성하지 않고 비공개(private)의 접근성을 가지므로 외부 호출을 차단할 수 있다. private 멤버 함수는 그 클래스의 멤버 함수와 friend 함수가 호출할 수 있으므로 아예 정의(define)하지 않아 링크 시점에서 .. 2021. 8. 26. Effective C++ | 항목 05 C++가 은근슬쩍 만들어 호출해버리는 함수들에 촉각을 세우자 항목 05 C++가 은근슬쩍 만들어 호출해버리는 함수들 5.1 컴파일러가 선언하는 디폴트 멤버 함수 컴파일러가 기본으로 선언하는 멤버 함수는 다음과 같다. 생성자(constructor) 복사 생성자(copy constructor) 소멸자(destructor) 복사 대입 연산자(copy assignment operator) 컴파일러가 만드는 함수는 모두 기본형(default)이고 public 멤버이며 inline 함수다. class Empty { }; class Empty { public: Empty() { ... };// 디폴트 생성자 Empty(const Empty& rhs) { ... };// 디폴트 복사 생성자 ~Empty() { ... };// 디폴트 소멸자 Empty& operator=(cons.. 2021. 8. 26. Effective C++ | 항목 04 객체를 사용하기 전에 반드시 그 객체를 초기화하자 항목 04 객체를 사용하기 전에 반드시 그 객체를 초기화하자 4.1 비멤버 객체 초기화 C++는 객체(변수)를 초기화하는 데 있어 언제 초기화가 보장되며 언제 그렇지 않은지 규칙이 명확하게 준비되어 있다. 그러나 안타까운 점은 그 규칙 자체가 머리에 새겨두기엔 너무 복잡하다는 것이다. 따라서 가장 좋은 방법은 모든 객체를 사용하기 전에 항상 초기화하는 것이다. 기본제공 타입으로 만들어진 비멤버 객체에 대해서는 초기화를 손수해야 한다. /* int의 직접 초기화 */ int x = 0; /* 포인터의 직접 초기화 */ const char* const text = "A C-style string"; /* 입력 스트림에서 읽음으로써 초기화 */ double d; std::cin >> d; 4.2 멤버 객체 초.. 2021. 8. 26. Effective C++ | 항목 03 낌새만 보이면 const를 들이대보자 2021. 8. 26. 이전 1 2 3 4 다음