반응형
0. 요약
- 인터페이스를 잘못 사용하지 못하도록 고민하자!!
- 사용자가 저지를만한 실수를 생각하자
- 새로운 타입을 들이고, 제약을 넣어 실수를 방지하자
- 특별한 이유가 없다면 기본 타입처럼 사용자 타입을 구현하자
- 일관성 있는 인터페이스를 제공하자
- 스마트 포인터를 써서 사용자 오류를 방지하자
1. 인터페이스를 잘 못 사용하지 못하도록 하자
- 사용자가 저지를만한 실수를 미리 생각하자!
- ex) 날짜를 나타내는 클래스
- 매개 변수를 잘 못 넣을 수 있음
class Date{
public:
Date(int month, int day, int year);
};
Date d(30, 3, 1995) ; // 3과 30을 잘못씀
Date d(3, 40, 1995); // 30을 넣어야했는데 오타로 40..
- 새로운 타입을 들여와 인터페이스를 강화하자!
- 일, 월, 연을 구분하는 랩퍼 타입을 만들자.
- 이 타입을 Date 생성자 안에 두자.
// 일 타입
struct Day{
explicit Day(int d) : val(d) {}
int val;
};
// 월 타입
struct Month{
explicit Month(int m) : val(m) {}
int val;
}
// 년 타입
struct Year {
explicit Year(int y) : val(y) {}
int val;
}
// Date 클래스 재정의
class Date{
public:
Date(const Month& m, const Day& d, const Year& y);
};
Date d(Month(3), Day(30), Year(1995));
- 새로운 타입에 제약을 넣어 오류를 방지하자!
- 월은 12개 값만 가지므로, 제약을 주자
class Month{
public:
static Month Jan() {return Month(1);}
...
static Month Dec() {return Month(12);}
private:
explicit Month(int m);
};
Date d(Month::Mar(), Day(30), Year(1995));
특별한 이유가 없다면, 사용자 정의 타입은 기본 제공 타입처럼 동작하게 하자!
- 항목 3의 if(a*b = c) 의 예제 참고
- operator*의 반환타입을 const로 한정하여, 사용자 실수로 인한 c 대입 방지 가능
일관성 있는 인터페이스를 제공하자
- STL 컨테이너는 대체로 일관성이 있어서 사용하기 편리하다.
- ex) STL 컨테이너는 size란 멤버 함수를 공통적으로 제공한다.
- length, size, count 등 혼용하면 헷갈린다.
2. 스마트 포인터 사용
- 사용자가 신경쓰지 않도록 하자(외우지 않도록)
- Factory 함수에서 포인터를 반환할 때 shared_ptr을 반환하여 메모리 누수 문제를 해결하자.
Investment* createInvestment(); // (X)
std::shared_ptr<Investment> createInvestment(); // (O)
- 스마트 포인터의 삭제자를 활용하자
- Investment* 포인터를 직접 삭제하지 않고, 별도 삭제자를 통해 삭제하자
- 하지만 별도 삭제자를 사용하지 않고 직접 delete를 할 가능성이 있다.
- 또한 실수로 delete를 하고, 삭제자도 호출 할 수도 있다.
- 아래와 같이 create할 때 삭제자가 포함된 shared_ptr을 반환하도록 구현
std::shared_ptr<Investment> createInvestment(){
// 방법 1. 포인터를 null ptr로 초기화 하고 나중에 대입하는 방석
std::shared<Investment> retVal(static_cast<Investment*>(0), getRidOfInvestment);
// 방법 2. 실제 객체 포인터를 바로 생성자에 넘기는 방법
std::shared_ptr<Investment> retVal(new Investment, getRidOfInvestment);
retVal = ...;
return retVal;
}
- shared_ptr은 '교차DLL 문제' 를 방지한다.
- 교차 DLL 문제 : 어떤 DLL에서 객체를 생성하고, 다른 DLL에서 소멸하는 문제
- 객체 생성/삭제가 서로 다른 DLL에서 호출될 때 발생
- shared_ptr은 생성된 DLL과 동일한 DLL에서 delete를 사용하도록 삭제자가 만들어져 있어서 방지 가능
// 아래 함수가 반환하는 shared_ptr은 다른 DLL 사이에 이리저리 넘겨져도 교차 DLL 문제를 걱정하지 않아도 된다.
std::shareD_ptr<Investment> createInvestment(){
return std::shared_ptr<Investment>(new Stock);
}
참고
- Effective C++
반응형
'C++ > Effective C++' 카테고리의 다른 글
[Effective C++] 20. 값에 의한 전달보다는 상수객체 참조자에 의한 전달 방식을 선택하는 편이 대개 낫다 (0) | 2021.03.15 |
---|---|
[Effective C++] 19. 클래스 설계는 타입 설계와 똑같이 취급하자 (0) | 2021.03.15 |
[Effective C++] 17. new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 (0) | 2021.03.15 |
[Effective C++] 16. new 및 delete를 사용할 때는 형태를 반드시 맞추자 (0) | 2021.03.15 |
[Effective C++] 15. 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자 (0) | 2021.03.15 |