Hyun2and
[Effective C++] 45: "호환되는 모든 타입" 을 받아들이는 데는 멤버 함수 템플릿이 직방! 본문
[Effective C++] 45: "호환되는 모든 타입" 을 받아들이는 데는 멤버 함수 템플릿이 직방!
혀니앤 2023. 7. 31. 18:16
(처음엔 이름이 길다고 생각했지만 보면 볼수록 항목 이름을 간결하게 잘 지은 것 같다)
포인트
모든 타입을 받아들이는 멤버 함수를 만들려면 멤버 함수 템플릿을 쓰면 된다
복사 생성자와 복사 대입 연산자는 직접 선언해야 한다!!
정리
- 스마트 포인터 : 힙 기반 자원을 타이밍맞게 삭제해준다 (항목 13 참고)
- 반복자 iterator : 단순연산을 지원한다 ( ++, -- 등)
포인터 : 암시적 변환을 지원함. 스마트포인터는 각 포인터들이 별개이기 때문에 변환 클래스를 직접 만들어야 한다
-> std::static_pointer_cast<T>() 을 쓰면 Cast 가 되는 것 아닌가?
책이 옛날책이라 auto_ptr 을 사용하는 예시를 쓰고있다 ! 항목13에는 shared_ptr 이 tr1 라이브러리 것인 것으로 쓰여있다
http://i5on9i.blogspot.com/2013/03/cc-tr1.html
TR1은 c++ 표준 라이브러리에 추가될 새로운 기능에 대한 스펙(specification)이다
책이 쓰여질 시기에는 아직 C++ 라이브러리에 추가되지 않아, 지금은 가지고 있는 함수들이 없었던 모양이다
https://openmynotepad.tistory.com/33
이 글에서는 auto_ptr 을 보완하여 unique_ptr 이 되었고, 이후 shared_ptr -> weak_ptr 까지 된 기록들이 이어져있다
타입 T를 받는 class 안에 타입 U를 받는 생성자 함수 템플릿을 만들어서 일반화 복사 생성자를 만들 수 있다.
그러나 이 경우, Drived -> Base 로 Cast 만 가능해야하는데, Base -> Drived 로도 Cast가 가능해진다
template<typename T>
class SmartPtr {
public :
template<typename U>
Smart(const SmartPtr<U>& other)
: heldPtr(other.get()) {}
T* get() const { return heldPtr; }
private:
T* heldPtr;
};
멤버 변수로 기본제공 포인터 T* 를 저장하고, 다른 스마트포인터의 값으로 초기화한다
shared_ptr 도 이 방법을 쓰고있는지 확인해보자
shared_ptr(const shared_ptr& _Other) noexcept { // construct shared_ptr object that owns same resource as _Other
this->_Copy_construct_from(_Other); //항목 43에서 확인한 템플릿 함수 명시화를 쓰고 있다!
}
shared_ptr의 생성 과정에서 위와 같이 다른 포인터로 생성하고자 하는 경우, 템플릿의 복사 함수를 호출한다
template <class _Ty2>
void _Copy_construct_from(const shared_ptr<_Ty2>& _Other) noexcept {
// implement shared_ptr's (converting) copy ctor
_Other._Incref(); //ref 를 증가시키는 함수
_Ptr = _Other._Ptr; //other 의 포인터를 복사한다!
_Rep = _Other._Rep;
}
shared_ptr 은 Ptr_base 를 상속받고 있으며, Ptr_base 의 복사 생성자 함수를 확인해보면,
함수의 Ptr 값을 가져와 넣어주고 있음을 알 수 있다.
복사 생성자, 복사 대입 연산자
컴파일러가 마음대로 생성하는 두 가지 클래스 멤버 함수. (+ 생성자, 소멸자까지)
위처럼 직접 복사 생성자를 만들었다고 해도, 두 가지는 따로 생성해줘야한다
_Ptr_base(const _Ptr_base&) = delete; //복사 생성자
_Ptr_base& operator=(const _Ptr_base&) = delete; //복사 대입 연산자
_Ptr_base 클래스는 두가지를 직접 delete 해주고 있다
shared_ptr& operator=(const shared_ptr& _Right) noexcept {
shared_ptr(_Right).swap(*this);
return *this;
}
template <class _Ty2>
shared_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept {
shared_ptr(_Right).swap(*this);
return *this;
}
shared_ptr 에서는 위처럼 기본 복사 대입 연산자와 일반화 복사 대입 연산자를 동시에 선언해주고 있다.
스마트포인터에 대해서도 알 수 있는 항목이었다
이것저것 알아보느라 시간은 더 오래걸렸지만 재밌었다 !
'공부엔 끝이없다 > Effective C++' 카테고리의 다른 글
[Effective C++] 46: 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자 (0) | 2023.08.06 |
---|---|
[Effective C++] 44: 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자 (0) | 2023.07.31 |
[Effective C++] 43: 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아두자 (1) | 2023.07.23 |
[Effective C++] 1. C++ (0) | 2023.02.19 |
[Effective C++] 0. 서론 (0) | 2023.02.19 |