Hyun2and

[Effective C++] 45: "호환되는 모든 타입" 을 받아들이는 데는 멤버 함수 템플릿이 직방! 본문

공부엔 끝이없다/Effective C++

[Effective C++] 45: "호환되는 모든 타입" 을 받아들이는 데는 멤버 함수 템플릿이 직방!

혀니앤 2023. 7. 31. 18:16
728x90

 

 

(처음엔 이름이 길다고 생각했지만 보면 볼수록 항목 이름을 간결하게 잘 지은 것 같다)

 

 

포인트

모든 타입을 받아들이는 멤버 함수를 만들려면 멤버 함수 템플릿을 쓰면 된다
복사 생성자와 복사 대입 연산자는 직접 선언해야 한다!!

 


정리

- 스마트 포인터 : 힙 기반 자원을 타이밍맞게 삭제해준다 (항목 13 참고)

- 반복자 iterator : 단순연산을 지원한다 ( ++, -- 등)

출처 : https://learn.microsoft.com/ko-kr/cpp/standard-library/iterator?view=msvc-170

 

포인터 : 암시적 변환을 지원함. 스마트포인터는 각 포인터들이 별개이기 때문에 변환 클래스를 직접 만들어야 한다

-> 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

 

C++11) 스마트 포인터 ( auto_ptr, unique_ptr, shared_ptr, weak_ptr)

이번엔 auto_ptr 부터 weak_ptr 까지 모든 스마트 포인터들에 대해 작성합니다. auto_ptr은 TR1 부터 생성됐던 스마트 포인터의 시초입니다.사용자가 깜빡 할 수 있는 동적할당 된 객체의 파괴를 대신 해

openmynotepad.tistory.com

이 글에서는 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 에서는 위처럼 기본 복사 대입 연산자와 일반화 복사 대입 연산자를 동시에 선언해주고 있다.

 


 

스마트포인터에 대해서도 알 수 있는 항목이었다

이것저것 알아보느라 시간은 더 오래걸렸지만 재밌었다 !

 

 

 

 

728x90
Comments