일지
-
Effective C++...14일지 2022. 6. 14. 07:42
자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 외부 접근이 필요한 이유와 방법 API를 사용하거나 하위 클래스의 함수가 필요한 경우 형 변환이 필요할 수 있다. 이때, 자원 관리 클래스 자체를 사용할 수 없으므로 자원에 접근할 방법이 필요하다. 자원의 외부 접근 방식은 다음 두 가지로 나뉜다. 암시적 변환 대입 연산을 통해 변환이 되도록 만드는 방법 명시적 변환 직접적으로 함수 호출을 통해 자원을 접근하는 방법 두 방법에 장단점이 있는데 암시적 변환은 코드 사용성이 증가하지만 위험성도 증가한다는 문제가 있고 명시적 변환은 그와 반대로 위험성은 낮지만 코드 사용성이 떨어지게 된다. 따라서 전체 프로그램의 방향성에 따라 적절한 방법을 선택하면 된다. ※ 자원 관리 클래스는 데이터 은닉..
-
Effective C++...13일지 2022. 6. 13. 07:50
자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자 스마트 포인터가 적합하지 않은 경우 힙에서 관리되는 자원이 아닌 경우에는 스마트 포인터로 처리하는 게 알맞지 않다. 이 경우 스스로 자원 관리 클래스를 만들어야 할 수 있다. 그 예로 뮤텍스를 관리하는 클래스가 있는 경우 다음과 같이 만들 수 있다. class Lock { public: explicit Lock(Mutex* pm) : mutexPtr(pm) { lock(mutexPtr); } // 생성자에서 락을 걸고 ~Lock() { unlock(mutexPtr); } // 소멸자에서 락을 해제한다. private: Mutex* mutexPtr; }; 자원 관리 클래스의 복사 처리 방법 자원 관리 클래스에서 복사가 필요한 경우 자신의 의도에 따라 ..
-
Effective C++...12일지 2022. 6. 12. 15:39
자원 관리에는 객체가 그만! 자원을 안전하게 사용할 수 있는 조건 자원 관리를 수동으로 하게 되면 예상하지 못한 시점에 함수가 반환되거나 예외가 발생하는 경우 처리가 어려워지게 된다. 이 것을 막기 위해 자원을 특정 객체에 넘기고 객체가 소멸될 때 자원을 삭제하도록 하면 안전하게 처리가 가능하다. 이 자원 관리 객체는 다음의 조건을 만족해야 한다. 자원을 획득한 후에 자원 관리 객체에게 넘긴다. 자원 관리 객체는 자신의 소멸자를 사용해서 자원이 확실하게 해제되도록 한다. 자원 관리 객체의 예와 주의 사항 대표적인 자원 관리 객체에는 스마트 포인터가 있다. 그런데 스마트 포인터는 객체의 제거 시 delete를 사용하기 때문에 배열을 동적 생성했을 때 안전하게 삭제해 줄 수 없다. 이러한 이유는 대부분의 배..
-
Effective C++...11일지 2022. 6. 10. 07:34
객체의 모든 부분을 빠짐없이 복사하자 객체를 복사하는 함수 캡슐화한 객체 지향 시스템에 객체를 복사하는 함수는 단 두 개만 존재하며 이를 객체 복사 함수라고 부른다. 복사 생성자 클래스 인스턴스의 레퍼런스를 인자로 받는 생성자 복사 대입 연산자 클래스 인스턴스의 레퍼런스를 인자로 받는 대입 연산자 문제가 발생하는 경우 문제가 되는 경우도 크게 두 가지가 있다. 객체 복사 함수를 따로 구현한 뒤 멤버 변수를 추가했는데 객체 복사 함수에는 추가하지 않은 경우 상속받은 경우 상위 클래스의 멤버 변수를 복사해주지 않은 경우 상위 클래스의 멤버 변수 복사 문제가 발생하는 경우에서 상위 클래스의 멤버 변수 복사는 상위 클래스의 객체 복사 함수를 호출해 주는 것으로 해결할 수 있다. class PriorityCust..
-
Effective C++...10일지 2022. 6. 9. 08:03
Operator=에서는 자기 대입에 대한 처리가 빠지지 않도록 하자 자기 대입이란? 어떤 객체가 자기 자신에 대해 대입 연산자를 적용하는 것을 말한다. class Widget { ... };Widget w; w = w; // 같은 변수에 대입하는 경우 a[i] = a[j]; // 만약 i와 j가 같은 경우 *px = *py; // 자기 대입이 될 가능성이 높음 자기 대입이 문제가 되는 경우 포인터를 사용하고 있고 대입할 때 기존 포인터 값을 삭제하고 대입하는 값을 복사해 사용하는 코드가 있을 때, 자기 대입이 발생한 경우 제거된 값을 복사하려고 시도하게 될 수 있다. // Widget에 Bitmap* pb가 있다. Widget& Widget::operator=(const Widget& rhs) { del..
-
Effective C++...9일지 2022. 6. 8. 07:26
대입 연산자는 *this의 참조자를 반환하게 하자 일종의 관례 대입 연산은 우측 연관 연산이라는 특성을 가지며 이는 대입 시 우측에 있는 인자의 값을 대입하는 방식으로 진행된다. 이때, 참조되는 값을 넘길 때 참조자를 반환하는 게 일종의 관례이다. int x, y, z; x = y = z = 15; // 이를 풀어쓰면 x = (y = (z = 15)); 이렇게 되는데, z에 15를 대입하고 y에 값이 대입된 z를 대입하고 x에는 또 y를 대입하는 식이다. class Widget { // 클래스 구현 시 모든 대입 연산자(=, +=, -= 등)는 *this의 참조자를 반환하는 게 좋다. public: Widget& operator=(const Widget& rhs) { return *this; //이렇게 ..
-
Effective C++...8일지 2022. 6. 7. 07:52
객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자 파생 클래스의 초기화 파생 클래스의 기본 클래스 초기화 시 파생 클래스는 기본 클래스로 결정된다. 즉, 기본 클래스 초기화 시에는 typeid 같은 것을 사용하더라도 기본 클래스로 나타나게 되며 가상 함수를 호출한다면 기본 클래스의 가상 함수가 호출될 것이다. class Transaction { public: Transaction(); virtual void logTransaction() const = 0; // 로그를 찍는 가상 함수가 있는 경우 }; Transaction::Transaction() { logTransaction(); // 이 경우 Transaction의 logTransaction을 호출하게 된다. } class Sell..
-
Effective C++...7일지 2022. 6. 6. 18:01
예외가 소멸자를 떠나지 못하도록 붙들어 놓자 소멸자에서 예외를 회피하는 방법 먼저, 소멸자에서 예외가 발생하는 경우 디버깅이 거의 불가능하므로 예외가 발생하지 않는 게 가장 좋다. 하지만 예외가 발생하는 경우엔 두 가지 방법으로 처리를 할 수 있다. 소멸자에서 예외 발생 시 로그를 출력하고 프로그램을 종료한다. 소멸자에서 예외 발생 시 로그를 출력하고 예외를 소멸시킨다. ※ 사용자에게 선택권이 없으므로 둘 다 좋은 방법은 아니다. 사용자에게 선택권을 부여하는 방법 소멸자에서 호출하던 Close 함수가 있었다면 이 함수를 사용자가 호출할 수 있도록 한다면 예외 발생 시 사용자 스스로 디버깅을 진행할 수 있게 된다. class DBConn { public: ... void close() { db.close(..