스콧 마이어스의 Effective C++을 읽고 개인 공부 목적으로 요약 작성한 글입니다!
💡 실제 자원을 직접 접근해야 하는 기존 API들도 많기 때문에,
RAII 클래스를 만들 때는 그 클래스가 관리하는 자원을 얻을 수 있는 방법을 열어주어야 한다!
💡 자원 접근은 명시적 변환 혹은 암시적 변환을 통해 가능하다
💡 안전성만을 고려하면 명시적 변환이 낫지만, 고객 편의성을 두고 보면 암시적 변환이 괜찮다!
std::tr1::shared_ptr<Investment> pInv(CreateInvestment());
int daysHeld(const Investment* pi);
int days = daysHeld(pInv); // Error!
이런 상황이 있을 수가 있슴
가끔 API들이 이렇게 객체를 직접 참조하도록 만들어진 경우가 있음.
daysHeld가 원하는건 Investment*
타입의 객체인데,
pInv는 shared_ptr<Investment>
의 객체잖어,,
그니까 에러가 나는거임!!
get()
멤버함수 사용스마트 포인터 객체에 들어있는 실제 포인터의 사본을 얻을 수 있다.
int days = daysHeld(pInv.get());
스마트 포인터 클래스에는 포인터 역참조 연산자를 오버로딩 하고 있다.
ex) operator->, operator*
class Investment {
public:
bool isTaxTree() const;
...
};
Investment* createInvestment();
shared_ptr<Investment> pi1(createInvestment());
bool texable1 = !(pi1->isTaxFree());
...
auto_ptr<Investment> pi2(createInvestment());
bool texable2 = !((*pi2).isTaxFree());
}
워뗘.
shared_ptr에서는 operator->을 써서 자원에 접근하고,
auto_ptr에서는 operator*을 써서 자원에 접근했다.
물론 예시니까 둘이 바꿔도 된당!
FontHandle getFont();
void releaseFont(FontHandle fh);
class Font {
public:
explicit Font(FontHandle fh) : f(fh) {}
~Font() { releaseFont(f); }
FontHandle get() const { return f; } // 명시적 변환 함수
operator FontHandle() const { return f; } // 암시적 변환 함수
private:
FontHandle f; // 실제 자원
};
void ChangeFontSize(FontHandle f, int newSize);
Font f(getFont());
int newFontSize;
...
ChangeFontSize(f.get(), newFontSize);
명시적 변환 함수가 get
멤버 함수를 쓴다고 했자나
근데 그러면 변환할 때마다 .get()을 매번 호출해야 하니까,, 넘 번거로움
그래서 암시적 변환 함수를 Font에서 제공한다 치면,
Font f(getFont());
int newFontSize;
...
changeFontSize(f, newFontSize);
이렇게 같은 상황에서 뚝딱.
Font에서 FontHandle로 변환을 해줘부럿다.
근데 이렇게 되면
Font f1(getFont());
...
FontHandle f2 = f1;
이런 상황에서,,
봐바
Font 타입의 f1을 복사해주고 싶었는데
FontHandle 타입으로 변해버렸잖어,,
이렇게,,
암시적 변환을 하면 원하지 않는 타입 변환이 일어날 수도 있다.
그래서 용도와 사용 환경에 따라서 명시적 / 암시적 변환 중 뭘 할지 고르면 된당!
😊 느낀점
.get() 으로 객체를 얻어오기
난 항상 명시적 변환을 했었다
아무래도,, 그게 익숙하고 좀 더 직관적이다
근데 그냥 명시적 변환을 쓰는게 좋을 것 같다
편의성은.. 솔직히 잘 몰겟다 ㅋ ㅋ