Shared_ptr
使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。在最后一个shared_ptr析构的时候,内存才被释放。
初始化
std::shared_ptr<int> p(new int(2));
p.reset(new int(1));
获取原始指针
std::shared_ptr<int> ptr(new int(1));
int* p=ptr.get();
指定删除器
void DeleteIntPtr(int* p)
{
delete P;
}
std::shard_ptr<int> p(new int, DeleteIntPtr);
std::shared_ptr<int> p(new int[10], [](int* p){delete[] p;});
使用shared_ptr注意的问题
1.用一个原始指针初始化多个shared_ptr
2.不要在函数市场中创建shared_ptr
funtion (shared_ptr<int>(new int),g());
3.通过shared_from_this返回this指针。不要将this指针左shared_ptr返回出来,因为this指针本质上是一个裸指针,会导致重复析构。
return shared_ptr<A)(this);xxxxxxxxxxxxxx
应该使用std::enable_shared_from_this<T>,然后基类的成员函数shared_from_this来返回this的shared_ptr
class A:public std::enable_shared_from_this<A>
{
std::shared_ptr<A> GetSelf(){
return shared_from_this();
}
}
4.避免重复引用。
class A{
std::shard_ptr<B> bptr;
}
class B{
std::shard_ptr<A> bp2;
}
unique_ptr独占共享指针
它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另外一个unique_ptr.
可以通过std::move来把指针交给其他unique_ptr.
unique_ptr指定删除器,需要指定删除器的类型。
std::unique_ptr<int,void(*)(int*)> ptr(niew int(1), [](int* p){delete p});
如果捕获了参数,需要使用如下:
std::unique_ptr<int, std::function<void(int*)>> ptr(niew int(1), [](int* p){delete p});
weak_ptr弱引用的智能指针
用来监视shard_ptr,不会使引用计数加1,不管理shared_ptr的内部指针。
1.通过use_count获取观察资源的引用计数
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
cout<<wp.use_count()<<endl;
2.通过expired()方法来判断观察到的资源是否已经被释放了
shared_ptr<int> sp(new int(10);
weak_ptr<int> wp(sp);
if(wp.expired())
3.通过lock来获取监控的shared_ptr
std::weak_ptr<int> gw;
gw.lock();
4.weak_ptr可以解决相互引用的问题
管理三方库:
std::shared_ptr<void> Guard(void* p){
return std::shared_ptr<void> sp(p, [this](void* p){Gethandle()->Release(p);});
}
void* p=Gethandle()->Create();
auto sp=Guard(p);
// CLASS TEMPLATE _Ptr_base
template<class _Ty>
class _Ptr_base
{ // base class for shared_ptr and weak_ptr
public:
using element_type = remove_extent_t<_Ty>;
_NODISCARD long use_count() const noexcept
{ // return use count
return (_Rep ? _Rep->_Use_count() : 0);
}
template<class _Ty2>
_NODISCARD bool owner_before(const _Ptr_base<_Ty2>& _Right) const noexcept
{ // compare addresses of manager objects
return (_Rep < _Right._Rep);
}
_Ptr_base(const _Ptr_base&) = delete;
_Ptr_base& operator=(const _Ptr_base&) = delete;
protected:
_NODISCARD element_type * get() const noexcept
{ // return pointer to resource
return (_Ptr);
}
constexpr _Ptr_base() noexcept = default;
~_Ptr_base() = default;
template<class _Ty2>
void _Move_construct_from(_Ptr_base<_Ty2>&& _Right)
{ // implement shared_ptr's (converting) move ctor and weak_ptr's move ctor
_Ptr = _Right._Ptr;
_Rep = _Right._Rep;
_Right._Ptr = nullptr;
_Right._Rep = nullptr;
}
template<class _Ty2>
void _Copy_construct_from(const shared_ptr<_Ty2>& _Other)
{ // implement shared_ptr's (converting) copy ctor
if (_Other._Rep)
{
_Other._Rep->_Incref();
}
_Ptr = _Other._Ptr;
_Rep = _Other._Rep;
}
template<class _Ty2>
void _Alias_construct_from(const shared_ptr<_Ty2>& _Other, element_type * _Px)
{ // implement shared_ptr's aliasing ctor
if (_Other._Rep)
{
_Other._Rep->_Incref();
}
_Ptr = _Px;
_Rep = _Other._Rep;
}
template<class _Ty0>
friend class weak_ptr; // specifically, weak_ptr::lock()
template<class _Ty2>
bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other)
{ // implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()
if (_Other._Rep && _Other._Rep->_Incref_nz())
{
_Ptr = _Other._Ptr;
_Rep = _Other._Rep;
return (true);
}
return (false);
}
void _Decref()
{ // decrement reference count
if (_Rep)
{
_Rep->_Decref();
}
}
void _Swap(_Ptr_base& _Right) noexcept
{ // swap pointers
_STD swap(_Ptr, _Right._Ptr);
_STD swap(_Rep, _Right._Rep);
}
void _Set_ptr_rep(element_type * _Other_ptr, _Ref_count_base * _Other_rep)
{ // take new resource
_Ptr = _Other_ptr;
_Rep = _Other_rep;
}
template<class _Ty2>
void _Weakly_construct_from(const _Ptr_base<_Ty2>& _Other)
{ // implement weak_ptr's ctors
if (_Other._Rep)
{
_Other._Rep->_Incwref();
}
_Ptr = _Other._Ptr;
_Rep = _Other._Rep;
}
void _Decwref()
{ // decrement weak reference count
if (_Rep)
{
_Rep->_Decwref();
}
}
private:
element_type * _Ptr{nullptr};
_Ref_count_base * _Rep{nullptr};
template<class _Ty0>
friend class _Ptr_base;
#if _HAS_STATIC_RTTI
template<class _Dx,
class _Ty0>
friend _Dx * get_deleter(const shared_ptr<_Ty0>& _Sx) noexcept;
#endif /* _HAS_STATIC_RTTI */
};
// CLASS TEMPLATE shared_ptr
template<class _Ty>
class shared_ptr
: public _Ptr_base<_Ty>
{ // class for reference counted resource management
private:
using _Mybase = _Ptr_base<_Ty>;
public:
using typename _Mybase::element_type;
#if _HAS_CXX17
using weak_type = weak_ptr<_Ty>;
#endif /* _HAS_CXX17 */
constexpr shared_ptr() noexcept
{ // construct empty shared_ptr
}
constexpr shared_ptr(nullptr_t) noexcept
{ // construct empty shared_ptr
}
template<class _Ux,
enable_if_t<conjunction_v<conditional_t<is_array_v<_Ty>, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>,
_SP_convertible<_Ux, _Ty>>, int> = 0>
explicit shared_ptr(_Ux * _Px)
{ // construct shared_ptr object that owns _Px
_Setp(_Px, is_array<_Ty>{});
}
template<class _Ux,
class _Dx,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, _Ux *&>,
_SP_convertible<_Ux, _Ty>>, int> = 0>
shared_ptr(_Ux * _Px, _Dx _Dt)
{ // construct with _Px, deleter
_Setpd(_Px, _STD move(_Dt));
}
template<class _Ux,
class _Dx,
class _Alloc,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, _Ux *&>,
_SP_convertible<_Ux, _Ty>>, int> = 0>
shared_ptr(_Ux * _Px, _Dx _Dt, _Alloc _Ax)
{ // construct with _Px, deleter, allocator
_Setpda(_Px, _STD move(_Dt), _Ax);
}
template<class _Dx,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, nullptr_t&>
>, int> = 0>
shared_ptr(nullptr_t, _Dx _Dt)
{ // construct with nullptr, deleter
_Setpd(nullptr, _STD move(_Dt));
}
template<class _Dx,
class _Alloc,
enable_if_t<conjunction_v<is_move_constructible<_Dx>,
_Can_call_function_object<_Dx&, nullptr_t&>
>, int> = 0>
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
{ // construct with nullptr, deleter, allocator
_Setpda(nullptr, _STD move(_Dt), _Ax);
}
template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Right, element_type * _Px) noexcept
{ // construct shared_ptr object that aliases _Right
this->_Alias_construct_from(_Right, _Px);
}
shared_ptr(const shared_ptr& _Other) noexcept
{ // construct shared_ptr object that owns same resource as _Other
this->_Copy_construct_from(_Other);
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr(const shared_ptr<_Ty2>& _Other) noexcept
{ // construct shared_ptr object that owns same resource as _Other
this->_Copy_construct_from(_Other);
}
shared_ptr(shared_ptr&& _Right) noexcept
{ // construct shared_ptr object that takes resource from _Right
this->_Move_construct_from(_STD move(_Right));
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr(shared_ptr<_Ty2>&& _Right) noexcept
{ // construct shared_ptr object that takes resource from _Right
this->_Move_construct_from(_STD move(_Right));
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
explicit shared_ptr(const weak_ptr<_Ty2>& _Other)
{ // construct shared_ptr object that owns resource *_Other
if (!this->_Construct_from_weak(_Other))
{
_THROW(bad_weak_ptr{});
}
}
#if _HAS_AUTO_PTR_ETC
template<class _Ty2,
enable_if_t<is_convertible_v<_Ty2 *, _Ty *>, int> = 0>
shared_ptr(auto_ptr<_Ty2>&& _Other)
{ // construct shared_ptr object that owns *_Other.get()
_Ty2 * _Px = _Other.get();
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ty2>(_Px));
_Other.release();
}
#endif /* _HAS_AUTO_PTR_ETC */
template<class _Ux,
class _Dx,
enable_if_t<conjunction_v<
_SP_pointer_compatible<_Ux, _Ty>,
is_convertible<typename unique_ptr<_Ux, _Dx>::pointer, element_type *>
>, int> = 0>
shared_ptr(unique_ptr<_Ux, _Dx>&& _Other)
{ // construct from unique_ptr
using _Fancy_t = typename unique_ptr<_Ux, _Dx>::pointer;
using _Raw_t = typename unique_ptr<_Ux, _Dx>::element_type *;
using _Deleter_t = conditional_t<is_reference_v<_Dx>, decltype(_STD ref(_Other.get_deleter())), _Dx>;
const _Fancy_t _Fancy = _Other.get();
if (_Fancy)
{
const _Raw_t _Raw = _Fancy;
const auto _Rx = new _Ref_count_resource<_Fancy_t, _Deleter_t>(_Fancy, _Other.get_deleter());
_Set_ptr_rep_and_enable_shared(_Raw, _Rx);
_Other.release();
}
}
~shared_ptr() noexcept
{ // release resource
this->_Decref();
}
shared_ptr& operator=(const shared_ptr& _Right) noexcept
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
template<class _Ty2>
shared_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
}
shared_ptr& operator=(shared_ptr&& _Right) noexcept
{ // take resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template<class _Ty2>
shared_ptr& operator=(shared_ptr<_Ty2>&& _Right) noexcept
{ // take resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
#if _HAS_AUTO_PTR_ETC
template<class _Ty2>
shared_ptr& operator=(auto_ptr<_Ty2>&& _Right)
{ // assign ownership of resource pointed to by _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
#endif /* _HAS_AUTO_PTR_ETC */
template<class _Ux,
class _Dx>
shared_ptr& operator=(unique_ptr<_Ux, _Dx>&& _Right)
{ // move from unique_ptr
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
void swap(shared_ptr& _Other) noexcept
{ // swap pointers
this->_Swap(_Other);
}
void reset() noexcept
{ // release resource and convert to empty shared_ptr object
shared_ptr().swap(*this);
}
template<class _Ux>
void reset(_Ux * _Px)
{ // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
}
template<class _Ux,
class _Dx>
void reset(_Ux * _Px, _Dx _Dt)
{ // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
}
template<class _Ux,
class _Dx,
class _Alloc>
void reset(_Ux * _Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, with deleter _Dt, allocator _Ax
shared_ptr(_Px, _Dt, _Ax).swap(*this);
}
using _Mybase::get;
template<class _Ty2 = _Ty,
enable_if_t<!disjunction_v<is_array<_Ty2>, is_void<_Ty2>>, int> = 0>
_NODISCARD _Ty2& operator*() const noexcept
{ // return reference to resource
return (*get());
}
template<class _Ty2 = _Ty,
enable_if_t<!is_array_v<_Ty2>, int> = 0>
_NODISCARD _Ty2 * operator->() const noexcept
{ // return pointer to resource
return (get());
}
template<class _Ty2 = _Ty,
class _Elem = element_type,
enable_if_t<is_array_v<_Ty2>, int> = 0>
_NODISCARD _Elem& operator[](ptrdiff_t _Idx) const
{ // subscript
return (get()[_Idx]);
}
_NODISCARD _CXX17_DEPRECATE_SHARED_PTR_UNIQUE bool unique() const noexcept
{ // return true if no other shared_ptr object owns this resource
return (this->use_count() == 1);
}
explicit operator bool() const noexcept
{ // test if shared_ptr object owns a resource
return (get() != nullptr);
}
private:
template<class _Ux>
void _Setp(_Ux * _Px, true_type)
{ // take ownership of _Px
_Setpd(_Px, default_delete<_Ux[]>{});
}
template<class _Ux>
void _Setp(_Ux * _Px, false_type)
{ // take ownership of _Px
_TRY_BEGIN // allocate control block and set
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ux>(_Px));
_CATCH_ALL // allocation failed, delete resource
delete _Px;
_RERAISE;
_CATCH_END
}
template<class _UxptrOrNullptr,
class _Dx>
void _Setpd(_UxptrOrNullptr _Px, _Dx _Dt)
{ // take ownership of _Px, deleter _Dt
_TRY_BEGIN // allocate control block and set
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count_resource<_UxptrOrNullptr, _Dx>(_Px, _STD move(_Dt)));
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
template<class _UxptrOrNullptr,
class _Dx,
class _Alloc>
void _Setpda(_UxptrOrNullptr _Px, _Dx _Dt, _Alloc _Ax)
{ // take ownership of _Px, deleter _Dt, allocator _Ax
using _Refd = _Ref_count_resource_alloc<_UxptrOrNullptr, _Dx, _Alloc>;
using _Alref_alloc = _Rebind_alloc_t<_Alloc, _Refd>;
using _Alref_traits = allocator_traits<_Alref_alloc>;
_Alref_alloc _Alref(_Ax);
_TRY_BEGIN // allocate control block and set
const auto _Pfancy = _Alref_traits::allocate(_Alref, 1);
_Refd * const _Pref = _Unfancy(_Pfancy);
_TRY_BEGIN
_Alref_traits::construct(_Alref, _Pref, _Px, _STD move(_Dt), _Ax);
_Set_ptr_rep_and_enable_shared(_Px, _Pref);
_CATCH_ALL
_Alref_traits::deallocate(_Alref, _Pfancy, 1);
_RERAISE;
_CATCH_END
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
template<class _Ty0,
class... _Types>
friend shared_ptr<_Ty0> make_shared(_Types&&... _Args);
template<class _Ty0,
class _Alloc,
class... _Types>
friend shared_ptr<_Ty0> allocate_shared(const _Alloc& _Al_arg, _Types&&... _Args);
template<class _Ux>
void _Set_ptr_rep_and_enable_shared(_Ux * _Px, _Ref_count_base * _Rx)
{ // take ownership of _Px
this->_Set_ptr_rep(_Px, _Rx);
_Enable_shared_from_this(*this, _Px);
}
void _Set_ptr_rep_and_enable_shared(nullptr_t, _Ref_count_base * _Rx)
{ // take ownership of nullptr
this->_Set_ptr_rep(nullptr, _Rx);
}
};
#if _HAS_CXX17
template<class _Ty>
shared_ptr(weak_ptr<_Ty>) -> shared_ptr<_Ty>;
template<class _Ty,
class _Dx>
shared_ptr(unique_ptr<_Ty, _Dx>) -> shared_ptr<_Ty>;
#endif /* _HAS_CXX17 */
template<class _Ty1,
class _Ty2>
_NODISCARD bool operator==(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept
{
return (_Left.get() == _Right.get());
}
template<class _Ty1,
class _Ty2>
_NODISCARD bool operator!=(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept
{
return (_Left.get() != _Right.get());
}
template<class _Ty1,
class _Ty2>
_NODISCARD bool operator<(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept
{
return (_Left.get() < _Right.get());
}
template<class _Ty1,
class _Ty2>
_NODISCARD bool operator>=(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept
{
return (_Left.get() >= _Right.get());
}
template<class _Ty1,
class _Ty2>
_NODISCARD bool operator>(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept
{
return (_Left.get() > _Right.get());
}
template<class _Ty1,
class _Ty2>
_NODISCARD bool operator<=(const shared_ptr<_Ty1>& _Left, const shared_ptr<_Ty2>& _Right) noexcept
{
return (_Left.get() <= _Right.get());
}
template<class _Ty>
_NODISCARD bool operator==(const shared_ptr<_Ty>& _Left, nullptr_t) noexcept
{
return (_Left.get() == nullptr);
}
template<class _Ty>
_NODISCARD bool operator==(nullptr_t, const shared_ptr<_Ty>& _Right) noexcept
{
return (nullptr == _Right.get());
}
template<class _Ty>
_NODISCARD bool operator!=(const shared_ptr<_Ty>& _Left, nullptr_t) noexcept
{
return (_Left.get() != nullptr);
}
template<class _Ty>
_NODISCARD bool operator!=(nullptr_t, const shared_ptr<_Ty>& _Right) noexcept
{
return (nullptr != _Right.get());
}
template<class _Ty>
_NODISCARD bool operator<(const shared_ptr<_Ty>& _Left, nullptr_t) noexcept
{
return (_Left.get() < static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr));
}
template<class _Ty>
_NODISCARD bool operator<(nullptr_t, const shared_ptr<_Ty>& _Right) noexcept
{
return (static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr) < _Right.get());
}
template<class _Ty>
_NODISCARD bool operator>=(const shared_ptr<_Ty>& _Left, nullptr_t) noexcept
{
return (_Left.get() >= static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr));
}
template<class _Ty>
_NODISCARD bool operator>=(nullptr_t, const shared_ptr<_Ty>& _Right) noexcept
{
return (static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr) >= _Right.get());
}
template<class _Ty>
_NODISCARD bool operator>(const shared_ptr<_Ty>& _Left, nullptr_t) noexcept
{
return (_Left.get() > static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr));
}
template<class _Ty>
_NODISCARD bool operator>(nullptr_t, const shared_ptr<_Ty>& _Right) noexcept
{
return (static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr) > _Right.get());
}
template<class _Ty>
_NODISCARD bool operator<=(const shared_ptr<_Ty>& _Left, nullptr_t) noexcept
{
return (_Left.get() <= static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr));
}
template<class _Ty>
_NODISCARD bool operator<=(nullptr_t, const shared_ptr<_Ty>& _Right) noexcept
{
return (static_cast<typename shared_ptr<_Ty>::element_type *>(nullptr) <= _Right.get());
}
template<class _Elem,
class _Traits,
class _Ty>
basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& _Out, const shared_ptr<_Ty>& _Px)
{ // write contained pointer to stream
return (_Out << _Px.get());
}
template<class _Ty>
void swap(shared_ptr<_Ty>& _Left, shared_ptr<_Ty>& _Right) noexcept
{ // swap _Left and _Right shared_ptrs
_Left.swap(_Right);
}
template<class _Ty1,
class _Ty2>
_NODISCARD shared_ptr<_Ty1> static_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept
{ // static_cast for shared_ptr that properly respects the reference count control block
const auto _Ptr = static_cast<typename shared_ptr<_Ty1>::element_type *>(_Other.get());
return (shared_ptr<_Ty1>(_Other, _Ptr));
}
template<class _Ty1,
class _Ty2>
_NODISCARD shared_ptr<_Ty1> const_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept
{ // const_cast for shared_ptr that properly respects the reference count control block
const auto _Ptr = const_cast<typename shared_ptr<_Ty1>::element_type *>(_Other.get());
return (shared_ptr<_Ty1>(_Other, _Ptr));
}
template<class _Ty1,
class _Ty2>
_NODISCARD shared_ptr<_Ty1> reinterpret_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept
{ // reinterpret_cast for shared_ptr that properly respects the reference count control block
const auto _Ptr = reinterpret_cast<typename shared_ptr<_Ty1>::element_type *>(_Other.get());
return (shared_ptr<_Ty1>(_Other, _Ptr));
}
#ifdef _CPPRTTI
template<class _Ty1,
class _Ty2>
_NODISCARD shared_ptr<_Ty1> dynamic_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept
{ // dynamic_cast for shared_ptr that properly respects the reference count control block
const auto _Ptr = dynamic_cast<typename shared_ptr<_Ty1>::element_type *>(_Other.get());
if (_Ptr)
{
return (shared_ptr<_Ty1>(_Other, _Ptr));
}
return (shared_ptr<_Ty1>());
}
#else /* _CPPRTTI */
template<class _Ty1,
class _Ty2>
shared_ptr<_Ty1> dynamic_pointer_cast(const shared_ptr<_Ty2>&) noexcept = delete; // requires /GR option
#endif /* _CPPRTTI */
#if _HAS_STATIC_RTTI
template<class _Dx,
class _Ty>
_NODISCARD _Dx * get_deleter(const shared_ptr<_Ty>& _Sx) noexcept
{ // return pointer to shared_ptr's deleter object if its type is _Dx
if (_Sx._Rep)
{
return (static_cast<_Dx *>(_Sx._Rep->_Get_deleter(typeid(_Dx))));
}
return (nullptr);
}
#else /* _HAS_STATIC_RTTI */
template<class _Dx,
class _Ty>
_Dx * get_deleter(const shared_ptr<_Ty>&) noexcept = delete; // requires static RTTI
#endif /* _HAS_STATIC_RTTI */
// CLASS TEMPLATE _Ref_count_obj
template<class _Ty>
class _Ref_count_obj
: public _Ref_count_base
{ // handle reference counting for object in control block, no allocator
public:
template<class... _Types>
explicit _Ref_count_obj(_Types&&... _Args)
: _Ref_count_base()
{ // construct from argument list
::new (static_cast<void *>(&_Storage)) _Ty(_STD forward<_Types>(_Args)...);
}
_Ty * _Getptr()
{ // get pointer
return (reinterpret_cast<_Ty *>(&_Storage));
}
private:
virtual void _Destroy() noexcept override
{ // destroy managed resource
_Getptr()->~_Ty();
}
virtual void _Delete_this() noexcept override
{ // destroy self
delete this;
}
aligned_union_t<1, _Ty> _Storage;
};
// CLASS TEMPLATE weak_ptr
template<class _Ty>
class weak_ptr
: public _Ptr_base<_Ty>
{ // class for pointer to reference counted resource
public:
constexpr weak_ptr() noexcept
{ // construct empty weak_ptr object
}
weak_ptr(const weak_ptr& _Other) noexcept
{ // construct weak_ptr object for resource pointed to by _Other
this->_Weakly_construct_from(_Other);
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept
{ // construct weak_ptr object for resource owned by _Other
this->_Weakly_construct_from(_Other);
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(const weak_ptr<_Ty2>& _Other) noexcept
{ // construct weak_ptr object for resource pointed to by _Other
this->_Weakly_construct_from(_Other.lock());
}
weak_ptr(weak_ptr&& _Other) noexcept
{ // move construct from _Other
this->_Move_construct_from(_STD move(_Other));
}
template<class _Ty2,
enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(weak_ptr<_Ty2>&& _Other) noexcept
{ // move construct from _Other
this->_Weakly_construct_from(_Other.lock());
_Other.reset();
}
~weak_ptr() noexcept
{ // release resource
this->_Decwref();
}
weak_ptr& operator=(const weak_ptr& _Right) noexcept
{ // assign from _Right
weak_ptr(_Right).swap(*this);
return (*this);
}
template<class _Ty2>
weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) noexcept
{ // assign from _Right
weak_ptr(_Right).swap(*this);
return (*this);
}
weak_ptr& operator=(weak_ptr&& _Right) noexcept
{ // move assign from _Right
weak_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template<class _Ty2>
weak_ptr& operator=(weak_ptr<_Ty2>&& _Right) noexcept
{ // move assign from _Right
weak_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
template<class _Ty2>
weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept
{ // assign from _Right
weak_ptr(_Right).swap(*this);
return (*this);
}
void reset() noexcept
{ // release resource, convert to null weak_ptr object
weak_ptr().swap(*this);
}
void swap(weak_ptr& _Other) noexcept
{ // swap pointers
this->_Swap(_Other);
}
_NODISCARD bool expired() const noexcept
{ // return true if resource no longer exists
return (this->use_count() == 0);
}
_NODISCARD shared_ptr<_Ty> lock() const noexcept
{ // convert to shared_ptr
shared_ptr<_Ty> _Ret;
(void) _Ret._Construct_from_weak(*this);
return (_Ret);
}
};
#if _HAS_CXX17
template<class _Ty>
weak_ptr(shared_ptr<_Ty>) -> weak_ptr<_Ty>;
#endif /* _HAS_CXX17 */
template<class _Ty>
void swap(weak_ptr<_Ty>& _Left, weak_ptr<_Ty>& _Right) noexcept
{ // swap contents of _Left and _Right
_Left.swap(_Right);
}
// CLASS TEMPLATE enable_shared_from_this
template<class _Ty>
class enable_shared_from_this
{ // provide member functions that create shared_ptr to this
public:
using _Esft_type = enable_shared_from_this;
_NODISCARD shared_ptr<_Ty> shared_from_this()
{ // return shared_ptr
return (shared_ptr<_Ty>(_Wptr));
}
_NODISCARD shared_ptr<const _Ty> shared_from_this() const
{ // return shared_ptr
return (shared_ptr<const _Ty>(_Wptr));
}
_NODISCARD weak_ptr<_Ty> weak_from_this() noexcept
{ // return weak_ptr
return (_Wptr);
}
_NODISCARD weak_ptr<const _Ty> weak_from_this() const noexcept
{ // return weak_ptr
return (_Wptr);
}
protected:
constexpr enable_shared_from_this() noexcept
: _Wptr()
{ // construct
}
enable_shared_from_this(const enable_shared_from_this&) noexcept
: _Wptr()
{ // construct (must value-initialize _Wptr)
}
enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept
{ // assign (must not change _Wptr)
return (*this);
}
~enable_shared_from_this() = default;
private:
template<class _Other,
class _Yty>
friend void _Enable_shared_from_this1(const shared_ptr<_Other>& _This, _Yty * _Ptr, true_type);
mutable weak_ptr<_Ty> _Wptr;
};
// CLASS TEMPLATE unique_ptr SCALAR
template<class _Ty,
class _Dx> // = default_delete<_Ty>
class unique_ptr
: public _Unique_ptr_base<_Ty, _Dx>
{ // non-copyable pointer to an object
public:
typedef _Unique_ptr_base<_Ty, _Dx> _Mybase;
typedef typename _Mybase::pointer pointer;
typedef _Ty element_type;
typedef _Dx deleter_type;
using _Mybase::get_deleter;
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
constexpr unique_ptr() noexcept
: _Mybase(pointer())
{ // default construct
}
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
constexpr unique_ptr(nullptr_t) noexcept
: _Mybase(pointer())
{ // null pointer construct
}
unique_ptr& operator=(nullptr_t) noexcept
{ // assign a null pointer
reset();
return (*this);
}
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
explicit unique_ptr(pointer _Ptr) noexcept
: _Mybase(_Ptr)
{ // construct with pointer
}
template<class _Dx2 = _Dx,
enable_if_t<is_constructible_v<_Dx2, const _Dx2&>, int> = 0>
unique_ptr(pointer _Ptr, const _Dx& _Dt) noexcept
: _Mybase(_Ptr, _Dt)
{ // construct with pointer and (maybe const) deleter&
}
template<class _Dx2 = _Dx,
enable_if_t<conjunction_v<negation<is_reference<_Dx2>>,
is_constructible<_Dx2, _Dx2>>, int> = 0>
unique_ptr(pointer _Ptr, _Dx&& _Dt) noexcept
: _Mybase(_Ptr, _STD move(_Dt))
{ // construct by moving deleter
}
template<class _Dx2 = _Dx,
enable_if_t<conjunction_v<is_reference<_Dx2>,
is_constructible<_Dx2, remove_reference_t<_Dx2>>>, int> = 0>
unique_ptr(pointer, remove_reference_t<_Dx>&&) = delete;
unique_ptr(unique_ptr&& _Right) noexcept
: _Mybase(_Right.release(),
_STD forward<_Dx>(_Right.get_deleter()))
{ // construct by moving _Right
}
template<class _Ty2,
class _Dx2,
enable_if_t<conjunction_v<negation<is_array<_Ty2>>,
is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>,
conditional_t<is_reference_v<_Dx>, is_same<_Dx2, _Dx>, is_convertible<_Dx2, _Dx>>
>, int> = 0>
unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right) noexcept
: _Mybase(_Right.release(),
_STD forward<_Dx2>(_Right.get_deleter()))
{ // construct by moving _Right
}
#if _HAS_AUTO_PTR_ETC
template<class _Ty2,
enable_if_t<conjunction_v<is_convertible<_Ty2 *, _Ty *>,
is_same<_Dx, default_delete<_Ty>>>, int> = 0>
unique_ptr(auto_ptr<_Ty2>&& _Right) noexcept
: _Mybase(_Right.release())
{ // construct by moving _Right
}
#endif /* _HAS_AUTO_PTR_ETC */
template<class _Ty2,
class _Dx2,
enable_if_t<conjunction_v<negation<is_array<_Ty2>>,
is_assignable<_Dx&, _Dx2>,
is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer, pointer>
>, int> = 0>
unique_ptr& operator=(unique_ptr<_Ty2, _Dx2>&& _Right) noexcept
{ // assign by moving _Right
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx2>(_Right.get_deleter());
return (*this);
}
unique_ptr& operator=(unique_ptr&& _Right) noexcept
{ // assign by moving _Right
if (this != _STD addressof(_Right))
{ // different, do the move
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
}
return (*this);
}
void swap(unique_ptr& _Right) noexcept
{ // swap elements
_Swap_adl(this->_Myptr(), _Right._Myptr());
_Swap_adl(this->get_deleter(), _Right.get_deleter());
}
~unique_ptr() noexcept
{ // destroy the object
if (get() != pointer())
{
this->get_deleter()(get());
}
}
_NODISCARD add_lvalue_reference_t<_Ty> operator*() const
{ // return reference to object
return (*get());
}
_NODISCARD pointer operator->() const noexcept
{ // return pointer to class object
return (this->_Myptr());
}
_NODISCARD pointer get() const noexcept
{ // return pointer to object
return (this->_Myptr());
}
explicit operator bool() const noexcept
{ // test for non-null pointer
return (get() != pointer());
}
pointer release() noexcept
{ // yield ownership of pointer
pointer _Ans = get();
this->_Myptr() = pointer();
return (_Ans);
}
void reset(pointer _Ptr = pointer()) noexcept
{ // establish new pointer
pointer _Old = get();
this->_Myptr() = _Ptr;
if (_Old != pointer())
{
this->get_deleter()(_Old);
}
}
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
// CLASS TEMPLATE unique_ptr ARRAY
template<class _Ty,
class _Dx>
class unique_ptr<_Ty[], _Dx>
: public _Unique_ptr_base<_Ty, _Dx>
{ // non-copyable pointer to an array object
public:
typedef _Unique_ptr_base<_Ty, _Dx> _Mybase;
typedef typename _Mybase::pointer pointer;
typedef _Ty element_type;
typedef _Dx deleter_type;
using _Mybase::get_deleter;
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
constexpr unique_ptr() noexcept
: _Mybase(pointer())
{ // default construct
}
template<class _Uty,
class _Is_nullptr = is_same<_Uty, nullptr_t>>
using _Enable_ctor_reset = enable_if_t<
is_same_v<_Uty, pointer>
|| _Is_nullptr::value
|| (is_same_v<pointer, element_type *>
&& is_pointer_v<_Uty>
&& is_convertible_v<
remove_pointer_t<_Uty>(*)[],
element_type(*)[]
>)>;
template<class _Uty,
class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0,
class = _Enable_ctor_reset<_Uty>>
explicit unique_ptr(_Uty _Ptr) noexcept
: _Mybase(_Ptr)
{ // construct with pointer
}
template<class _Uty,
class _Dx2 = _Dx,
enable_if_t<is_constructible_v<_Dx2, const _Dx2&>, int> = 0,
class = _Enable_ctor_reset<_Uty>>
unique_ptr(_Uty _Ptr, const _Dx& _Dt) noexcept
: _Mybase(_Ptr, _Dt)
{ // construct with pointer and (maybe const) deleter&
}
template<class _Uty,
class _Dx2 = _Dx,
enable_if_t<conjunction_v<negation<is_reference<_Dx2>>,
is_constructible<_Dx2, _Dx2>>, int> = 0,
class = _Enable_ctor_reset<_Uty>>
unique_ptr(_Uty _Ptr, _Dx&& _Dt) noexcept
: _Mybase(_Ptr, _STD move(_Dt))
{ // construct by moving deleter
}
template<class _Uty,
class _Dx2 = _Dx,
enable_if_t<conjunction_v<is_reference<_Dx2>,
is_constructible<_Dx2, remove_reference_t<_Dx2>>>, int> = 0>
unique_ptr(_Uty, remove_reference_t<_Dx>&&) = delete;
unique_ptr(unique_ptr&& _Right) noexcept
: _Mybase(_Right.release(),
_STD forward<_Dx>(_Right.get_deleter()))
{ // construct by moving _Right
}
unique_ptr& operator=(unique_ptr&& _Right) noexcept
{ // assign by moving _Right
if (this != _STD addressof(_Right))
{ // different, do the swap
reset(_Right.release());
this->get_deleter() = _STD move(_Right.get_deleter());
}
return (*this);
}
template<class _Uty,
class _Ex,
class _More,
class _UP_pointer = typename unique_ptr<_Uty, _Ex>::pointer,
class _UP_element_type = typename unique_ptr<_Uty, _Ex>::element_type>
using _Enable_conversion = enable_if_t<conjunction_v<
is_array<_Uty>,
is_same<pointer, element_type *>,
is_same<_UP_pointer, _UP_element_type *>,
is_convertible<_UP_element_type(*)[], element_type(*)[]>,
_More>>;
template<class _Uty,
class _Ex,
class = _Enable_conversion<_Uty, _Ex,
conditional_t<is_reference_v<_Dx>, is_same<_Ex, _Dx>, is_convertible<_Ex, _Dx>>>>
unique_ptr(unique_ptr<_Uty, _Ex>&& _Right) noexcept
: _Mybase(_Right.release(),
_STD forward<_Ex>(_Right.get_deleter()))
{ // construct by moving _Right
}
template<class _Uty,
class _Ex,
class = _Enable_conversion<_Uty, _Ex, is_assignable<_Dx&, _Ex>>>
unique_ptr& operator=(unique_ptr<_Uty, _Ex>&& _Right) noexcept
{ // assign by moving _Right
reset(_Right.release());
this->get_deleter() = _STD forward<_Ex>(_Right.get_deleter());
return (*this);
}
template<class _Dx2 = _Dx,
_Unique_ptr_enable_default_t<_Dx2> = 0>
constexpr unique_ptr(nullptr_t) noexcept
: _Mybase(pointer())
{ // null pointer construct
}
unique_ptr& operator=(nullptr_t) noexcept
{ // assign a null pointer
reset();
return (*this);
}
void reset(nullptr_t = nullptr) noexcept
{ // establish new null pointer
reset(pointer());
}
void swap(unique_ptr& _Right) noexcept
{ // swap elements
_Swap_adl(this->_Myptr(), _Right._Myptr());
_Swap_adl(this->get_deleter(), _Right.get_deleter());
}
~unique_ptr() noexcept
{ // destroy the object
_Delete();
}
_NODISCARD _Ty& operator[](size_t _Idx) const
{ // return reference to object
return (get()[_Idx]);
}
_NODISCARD pointer get() const noexcept
{ // return pointer to object
return (this->_Myptr());
}
explicit operator bool() const noexcept
{ // test for non-null pointer
return (get() != pointer());
}
pointer release() noexcept
{ // yield ownership of pointer
pointer _Ans = get();
this->_Myptr() = pointer();
return (_Ans);
}
template<class _Uty,
class = _Enable_ctor_reset<_Uty, false_type>>
void reset(_Uty _Ptr) noexcept
{ // establish new pointer
pointer _Old = get();
this->_Myptr() = _Ptr;
if (_Old != pointer())
{
this->get_deleter()(_Old);
}
}
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
private:
void _Delete()
{ // delete the pointer
if (get() != pointer())
{
this->get_deleter()(get());
}
}
};
// FUNCTION TEMPLATE make_unique
template<class _Ty,
class... _Types,
enable_if_t<!is_array_v<_Ty>, int> = 0>
_NODISCARD inline unique_ptr<_Ty> make_unique(_Types&&... _Args)
{ // make a unique_ptr
return (unique_ptr<_Ty>(new _Ty(_STD forward<_Types>(_Args)...)));
}
template<class _Ty,
enable_if_t<is_array_v<_Ty> && extent_v<_Ty> == 0, int> = 0>
_NODISCARD inline unique_ptr<_Ty> make_unique(size_t _Size)
{ // make a unique_ptr
typedef remove_extent_t<_Ty> _Elem;
return (unique_ptr<_Ty>(new _Elem[_Size]()));
}
template<class _Ty,
class... _Types,
enable_if_t<extent_v<_Ty> != 0, int> = 0>
void make_unique(_Types&&...) = delete;