https://en.cppreference.com/w/cpp/language/raii
https://docs.microsoft.com/en-us/cpp/cpp/object-lifetime-and-resource-management-modern-cpp?view=msvc-170
智能指针
C++提供了几种智能指针的实现,包括auto_ptr、unique_ptr、shared_ptr、weak_ptr,它们都是一些类模版。其中auto_ptr自C++11开始已经废弃。
C++的智能指针为指针(主要是对象资源)提供了一种有限的垃圾回收(garbage collection)功能。相较于其他高级语言的GC支持,C++智能指针提供的这种有限的垃圾回收实在是低级。
如下面的示例中,不管是auto_ptr、unique_ptr或者shared_ptr,都不能保证对象资源能够被正确的释放回收。
int *i = new int(100);
std::***_ptr<int> p1(i);
std::***_ptr<int> p2(i);
unique_ptr
unique_ptr定义如下:
template <class T, class D = default_delete<T>> class unique_ptr { public: typedef see below pointer; typedef T element_type; typedef D deleter_type; // constructors constexpr unique_ptr() noexcept; explicit unique_ptr(pointer p) noexcept; unique_ptr(pointer p, see below d1) noexcept; unique_ptr(pointer p, see below d2) noexcept; unique_ptr(unique_ptr&& u) noexcept; unique_ptr(nullptr_t) noexcept : unique_ptr() { } template <class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept; template <class U> unique_ptr(auto_ptr<U>&& u) noexcept; // destructor ~unique_ptr(); // assignment unique_ptr& operator=(unique_ptr&& u) noexcept; template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept; unique_ptr& operator=(nullptr_t) noexcept; // observers typename add_lvalue_reference<T>::type operator*() const; pointer operator->() const noexcept; pointer get() const noexcept; deleter_type& get_deleter() noexcept; const deleter_type& get_deleter() const noexcept; explicit operator bool() const noexcept; // modifiers pointer release() noexcept; void reset(pointer p = pointer()) noexcept; void swap(unique_ptr& u) noexcept; };
这里需要注意下几个typedef,element_type、deleter_type这两个还好理解,对应模板参数中的T、D。pointer的定义就不好理解了,除了知道pointer是一个定义的类型之外,“see below”是什么东西?typedef see below pointer;这样的typedef感觉就不是个正经typedef,而且pointer和“see below”还出现了好几次。
上面定义中的“see below”让人感觉一头雾水,包括C++标准中很有很多这样的“see below”,可以看下面的定义。
pointer
定义如下:
typedef typename __pointer_type<_Tp, deleter_type>::type pointer;
pointer的类型定义为__pointer_type<_Tp, deleter_type>中的type类型。
其中__pointer_type定义如下:
template <class _Tp, class _Dp> struct __pointer_type { typedef typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type type; };
这里的type类型定义为__pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>中的type类型。
在__pointer_type_imp命名空间中,__pointer_type定义如下:
template <class _Tp, class _Dp, bool = __has_pointer_type<_Dp>::value> struct __pointer_type { typedef typename _Dp::pointer type; };
下面是__pointer_type的一个模板特化,__pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>中的type类型就是下面的特化中的type类型,而这个type的类型其实就是模板参数_Tp的指针类型。
template <class _Tp, class _Dp> struct __pointer_type<_Tp, _Dp, false> { typedef _Tp* type; };
根据上面的分析,unique_ptr中的pointer类型其实就是模板参数T的指针类型。即
typedef see below pointer;
等价于
typedef T* pointer;
根据下面的定义,
template <class _T1, class _T2> class __compressed_pair : private __libcpp_compressed_pair_imp<_T1, _T2> { typedef __libcpp_compressed_pair_imp<_T1, _T2> base; public: typedef typename base::_T1_param _T1_param; typedef typename base::_T2_param _T2_param; typedef typename base::_T1_reference _T1_reference; typedef typename base::_T2_reference _T2_reference; typedef typename base::_T1_const_reference _T1_const_reference; typedef typename base::_T2_const_reference _T2_const_reference; _LIBCPP_INLINE_VISIBILITY __compressed_pair() {} _LIBCPP_INLINE_VISIBILITY explicit __compressed_pair(_T1_param __t1) : base(_VSTD::forward<_T1_param>(__t1)) {} _LIBCPP_INLINE_VISIBILITY explicit __compressed_pair(_T2_param __t2) : base(_VSTD::forward<_T2_param>(__t2)) {} _LIBCPP_INLINE_VISIBILITY __compressed_pair(_T1_param __t1, _T2_param __t2) : base(_VSTD::forward<_T1_param>(__t1), _VSTD::forward<_T2_param>(__t2)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __compressed_pair(const __compressed_pair& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : base(__p) {} _LIBCPP_INLINE_VISIBILITY __compressed_pair& operator=(const __compressed_pair& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) { base::operator=(__p); return *this; } _LIBCPP_INLINE_VISIBILITY __compressed_pair(__compressed_pair&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : base(_VSTD::move(__p)) {} _LIBCPP_INLINE_VISIBILITY __compressed_pair& operator=(__compressed_pair&& __p) _NOEXCEPT_(is_nothrow_move_assignable<_T1>::value && is_nothrow_move_assignable<_T2>::value) { base::operator=(_VSTD::move(__p)); return *this; } #endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS template <class... _Args1, class... _Args2> _LIBCPP_INLINE_VISIBILITY __compressed_pair(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args) : base(__pc, _VSTD::move(__first_args), _VSTD::move(__second_args), typename __make_tuple_indices<sizeof...(_Args1)>::type(), typename __make_tuple_indices<sizeof...(_Args2) >::type()) {} #endif // _LIBCPP_HAS_NO_VARIADICS _LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return base::first();} _LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return base::first();} _LIBCPP_INLINE_VISIBILITY _T2_reference second() _NOEXCEPT {return base::second();} _LIBCPP_INLINE_VISIBILITY _T2_const_reference second() const _NOEXCEPT {return base::second();} _LIBCPP_INLINE_VISIBILITY void swap(__compressed_pair& __x) _NOEXCEPT_(__is_nothrow_swappable<_T1>::value && __is_nothrow_swappable<_T2>::value) {base::swap(__x);} };
_VSTD在/c++/v1/__config中定义为
#define _VSTD std::_LIBCPP_NAMESPACE
#define _VSTD std::_LIBCPP_NAMESPACE
#define _VSTD std
#define _VSTD std::_LIBCPP_NAMESPACE
__compressed_pair继承(private)了__libcpp_compressed_pair_imp
template <class _T1, class _T2, unsigned = __libcpp_compressed_pair_switch<_T1, _T2>::value> class __libcpp_compressed_pair_imp;
下面是__libcpp_compressed_pair_imp的几个模板特化
0
template <class _T1, class _T2> class __libcpp_compressed_pair_imp<_T1, _T2, 0> { private: _T1 __first_; _T2 __second_; public: typedef _T1 _T1_param; typedef _T2 _T2_param; typedef typename remove_reference<_T1>::type& _T1_reference; typedef typename remove_reference<_T2>::type& _T2_reference; typedef const typename remove_reference<_T1>::type& _T1_const_reference; typedef const typename remove_reference<_T2>::type& _T2_const_reference; _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp() : __first_(), __second_() {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T1_param __t1) : __first_(_VSTD::forward<_T1_param>(__t1)), __second_() {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T2_param __t2) : __first_(), __second_(_VSTD::forward<_T2_param>(__t2)) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : __first_(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : __first_(__p.first()), __second_(__p.second()) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) { __first_ = __p.first(); __second_ = __p.second(); return *this; } _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : __first_(_VSTD::forward<_T1>(__p.first())), __second_(_VSTD::forward<_T2>(__p.second())) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_assignable<_T1>::value && is_nothrow_move_assignable<_T2>::value) { __first_ = _VSTD::forward<_T1>(__p.first()); __second_ = _VSTD::forward<_T2>(__p.second()); return *this; } #endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2> _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args, __tuple_indices<_I1...>, __tuple_indices<_I2...>) : __first_(_VSTD::forward<_Args1>(_VSTD::get<_I1>(__first_args))...), __second_(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...) {} #endif // _LIBCPP_HAS_NO_VARIADICS _LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return __first_;} _LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return __first_;} _LIBCPP_INLINE_VISIBILITY _T2_reference second() _NOEXCEPT {return __second_;} _LIBCPP_INLINE_VISIBILITY _T2_const_reference second() const _NOEXCEPT {return __second_;} _LIBCPP_INLINE_VISIBILITY void swap(__libcpp_compressed_pair_imp& __x) _NOEXCEPT_(__is_nothrow_swappable<_T1>::value && __is_nothrow_swappable<_T2>::value) { using _VSTD::swap; swap(__first_, __x.__first_); swap(__second_, __x.__second_); } };
1
template <class _T1, class _T2> class __libcpp_compressed_pair_imp<_T1, _T2, 1> : private _T1 { private: _T2 __second_; public: typedef _T1 _T1_param; typedef _T2 _T2_param; typedef _T1& _T1_reference; typedef typename remove_reference<_T2>::type& _T2_reference; typedef const _T1& _T1_const_reference; typedef const typename remove_reference<_T2>::type& _T2_const_reference; _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp() : __second_() {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T1_param __t1) : _T1(_VSTD::forward<_T1_param>(__t1)), __second_() {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T2_param __t2) : __second_(_VSTD::forward<_T2_param>(__t2)) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : _T1(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : _T1(__p.first()), __second_(__p.second()) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) { _T1::operator=(__p.first()); __second_ = __p.second(); return *this; } _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : _T1(_VSTD::move(__p.first())), __second_(_VSTD::forward<_T2>(__p.second())) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_assignable<_T1>::value && is_nothrow_move_assignable<_T2>::value) { _T1::operator=(_VSTD::move(__p.first())); __second_ = _VSTD::forward<_T2>(__p.second()); return *this; } #endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2> _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args, __tuple_indices<_I1...>, __tuple_indices<_I2...>) : _T1(_VSTD::forward<_Args1>(_VSTD::get<_I1>(__first_args))...), __second_(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...) {} #endif // _LIBCPP_HAS_NO_VARIADICS _LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY _T2_reference second() _NOEXCEPT {return __second_;} _LIBCPP_INLINE_VISIBILITY _T2_const_reference second() const _NOEXCEPT {return __second_;} _LIBCPP_INLINE_VISIBILITY void swap(__libcpp_compressed_pair_imp& __x) _NOEXCEPT_(__is_nothrow_swappable<_T1>::value && __is_nothrow_swappable<_T2>::value) { using _VSTD::swap; swap(__second_, __x.__second_); } };
2
template <class _T1, class _T2> class __libcpp_compressed_pair_imp<_T1, _T2, 2> : private _T2 { private: _T1 __first_; public: typedef _T1 _T1_param; typedef _T2 _T2_param; typedef typename remove_reference<_T1>::type& _T1_reference; typedef _T2& _T2_reference; typedef const typename remove_reference<_T1>::type& _T1_const_reference; typedef const _T2& _T2_const_reference; _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp() : __first_() {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T1_param __t1) : __first_(_VSTD::forward<_T1_param>(__t1)) {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T2_param __t2) : _T2(_VSTD::forward<_T2_param>(__t2)), __first_() {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : _T2(_VSTD::forward<_T2_param>(__t2)), __first_(_VSTD::forward<_T1_param>(__t1)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : _T2(__p.second()), __first_(__p.first()) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) { _T2::operator=(__p.second()); __first_ = __p.first(); return *this; } _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : _T2(_VSTD::forward<_T2>(__p.second())), __first_(_VSTD::move(__p.first())) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_assignable<_T1>::value && is_nothrow_move_assignable<_T2>::value) { _T2::operator=(_VSTD::forward<_T2>(__p.second())); __first_ = _VSTD::move(__p.first()); return *this; } #endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2> _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args, __tuple_indices<_I1...>, __tuple_indices<_I2...>) : _T2(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...), __first_(_VSTD::forward<_Args1>(_VSTD::get<_I1>(__first_args))...) {} #endif // _LIBCPP_HAS_NO_VARIADICS _LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return __first_;} _LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return __first_;} _LIBCPP_INLINE_VISIBILITY _T2_reference second() _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY _T2_const_reference second() const _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY void swap(__libcpp_compressed_pair_imp& __x) _NOEXCEPT_(__is_nothrow_swappable<_T1>::value && __is_nothrow_swappable<_T2>::value) { using _VSTD::swap; swap(__first_, __x.__first_); } };
3
template <class _T1, class _T2> class __libcpp_compressed_pair_imp<_T1, _T2, 3> : private _T1, private _T2 { public: typedef _T1 _T1_param; typedef _T2 _T2_param; typedef _T1& _T1_reference; typedef _T2& _T2_reference; typedef const _T1& _T1_const_reference; typedef const _T2& _T2_const_reference; _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp() {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T1_param __t1) : _T1(_VSTD::forward<_T1_param>(__t1)) {} _LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T2_param __t2) : _T2(_VSTD::forward<_T2_param>(__t2)) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : _T1(_VSTD::forward<_T1_param>(__t1)), _T2(_VSTD::forward<_T2_param>(__t2)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : _T1(__p.first()), _T2(__p.second()) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) { _T1::operator=(__p.first()); _T2::operator=(__p.second()); return *this; } _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : _T1(_VSTD::move(__p.first())), _T2(_VSTD::move(__p.second())) {} _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp& operator=(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_assignable<_T1>::value && is_nothrow_move_assignable<_T2>::value) { _T1::operator=(_VSTD::move(__p.first())); _T2::operator=(_VSTD::move(__p.second())); return *this; } #endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2> _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args, __tuple_indices<_I1...>, __tuple_indices<_I2...>) : _T1(_VSTD::forward<_Args1>(_VSTD::get<_I1>(__first_args))...), _T2(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...) {} #endif // _LIBCPP_HAS_NO_VARIADICS _LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY _T2_reference second() _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY _T2_const_reference second() const _NOEXCEPT {return *this;} _LIBCPP_INLINE_VISIBILITY void swap(__libcpp_compressed_pair_imp&) _NOEXCEPT_(__is_nothrow_swappable<_T1>::value && __is_nothrow_swappable<_T2>::value) { } };
构造
constexpr unique_ptr() noexcept;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(pointer()) { static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter"); }
explicit unique_ptr(pointer p) noexcept;
_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) _NOEXCEPT : __ptr_(_VSTD::move(__p)) { static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter"); }
unique_ptr(pointer p, see below d1) noexcept;
unique_ptr(pointer p, see below d2) noexcept;
unique_ptr(unique_ptr&& u) noexcept;
unique_ptr(nullptr_t) noexcept : unique_ptr() { }
还有两个构造函数是函数模板,构造函数是模板的不多见。
template <class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept;
template <class U> unique_ptr(auto_ptr<U>&& u) noexcept;
template <class _Tp, class _Dp = default_delete<_Tp> > class _LIBCPP_TYPE_VIS_ONLY unique_ptr { public: typedef _Tp element_type; typedef _Dp deleter_type; typedef typename __pointer_type<_Tp, deleter_type>::type pointer; private: __compressed_pair<pointer, deleter_type> __ptr_; #ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES unique_ptr(unique_ptr&); template <class _Up, class _Ep> unique_ptr(unique_ptr<_Up, _Ep>&); unique_ptr& operator=(unique_ptr&); template <class _Up, class _Ep> unique_ptr& operator=(unique_ptr<_Up, _Ep>&); #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES struct __nat {int __for_bool_;}; typedef typename remove_reference<deleter_type>::type& _Dp_reference; typedef const typename remove_reference<deleter_type>::type& _Dp_const_reference; public: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(pointer()) { static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter"); } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT : __ptr_(pointer()) { static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter"); } _LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) _NOEXCEPT : __ptr_(_VSTD::move(__p)) { static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter"); } #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename conditional< is_reference<deleter_type>::value, deleter_type, typename add_lvalue_reference<const deleter_type>::type>::type __d) _NOEXCEPT : __ptr_(__p, __d) {} _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename remove_reference<deleter_type>::type&& __d) _NOEXCEPT : __ptr_(__p, _VSTD::move(__d)) { static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference"); } _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) {} template <class _Up, class _Ep> _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr<_Up, _Ep>&& __u, typename enable_if < !is_array<_Up>::value && is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && is_convertible<_Ep, deleter_type>::value && ( !is_reference<deleter_type>::value || is_same<deleter_type, _Ep>::value ), __nat >::type = __nat()) _NOEXCEPT : __ptr_(__u.release(), _VSTD::forward<_Ep>(__u.get_deleter())) {} template <class _Up> _LIBCPP_INLINE_VISIBILITY unique_ptr(auto_ptr<_Up>&& __p, typename enable_if< is_convertible<_Up*, _Tp*>::value && is_same<_Dp, default_delete<_Tp> >::value, __nat >::type = __nat()) _NOEXCEPT : __ptr_(__p.release()) { } _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT { reset(__u.release()); __ptr_.second() = _VSTD::forward<deleter_type>(__u.get_deleter()); return *this; } template <class _Up, class _Ep> _LIBCPP_INLINE_VISIBILITY typename enable_if < !is_array<_Up>::value && is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && is_assignable<deleter_type&, _Ep&&>::value, unique_ptr& >::type operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT { reset(__u.release()); __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); return *this; } #else // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY operator __rv<unique_ptr>() { return __rv<unique_ptr>(*this); } _LIBCPP_INLINE_VISIBILITY unique_ptr(__rv<unique_ptr> __u) : __ptr_(__u->release(), _VSTD::forward<deleter_type>(__u->get_deleter())) {} template <class _Up, class _Ep> _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr<_Up, _Ep> __u) { reset(__u.release()); __ptr_.second() = _VSTD::forward<deleter_type>(__u.get_deleter()); return *this; } _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, deleter_type __d) : __ptr_(_VSTD::move(__p), _VSTD::move(__d)) {} template <class _Up> _LIBCPP_INLINE_VISIBILITY typename enable_if< is_convertible<_Up*, _Tp*>::value && is_same<_Dp, default_delete<_Tp> >::value, unique_ptr& >::type operator=(auto_ptr<_Up> __p) {reset(__p.release()); return *this;} #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY ~unique_ptr() {reset();} _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(nullptr_t) _NOEXCEPT { reset(); return *this; } _LIBCPP_INLINE_VISIBILITY typename add_lvalue_reference<_Tp>::type operator*() const {return *__ptr_.first();} _LIBCPP_INLINE_VISIBILITY pointer operator->() const _NOEXCEPT {return __ptr_.first();} _LIBCPP_INLINE_VISIBILITY pointer get() const _NOEXCEPT {return __ptr_.first();} _LIBCPP_INLINE_VISIBILITY _Dp_reference get_deleter() _NOEXCEPT {return __ptr_.second();} _LIBCPP_INLINE_VISIBILITY _Dp_const_reference get_deleter() const _NOEXCEPT {return __ptr_.second();} _LIBCPP_INLINE_VISIBILITY _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {return __ptr_.first() != nullptr;} _LIBCPP_INLINE_VISIBILITY pointer release() _NOEXCEPT { pointer __t = __ptr_.first(); __ptr_.first() = pointer(); return __t; } _LIBCPP_INLINE_VISIBILITY void reset(pointer __p = pointer()) _NOEXCEPT { pointer __tmp = __ptr_.first(); __ptr_.first() = __p; if (__tmp) __ptr_.second()(__tmp); } _LIBCPP_INLINE_VISIBILITY void swap(unique_ptr& __u) _NOEXCEPT {__ptr_.swap(__u.__ptr_);} };
参考libstdc++-v3/include/bits/unique_ptr.h
template <typename _Tp, typename _Dp = default_delete<_Tp>> class unique_ptr { template <typename _Up> using _DeleterConstraint = typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; __uniq_ptr_data<_Tp, _Dp> _M_t; public: using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; using element_type = _Tp; using deleter_type = _Dp; private: // helper template for detecting a safe conversion from another // unique_ptr template<typename _Up, typename _Ep> using __safe_conversion_up = __and_< is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, __not_<is_array<_Up>> >; public: // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr unique_ptr() noexcept : _M_t() { } /** Takes ownership of a pointer. * * @param __p A pointer to an object of @c element_type * * The deleter will be value-initialized. */ template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> _GLIBCXX23_CONSTEXPR explicit unique_ptr(pointer __p) noexcept : _M_t(__p) { } /** Takes ownership of a pointer. * * @param __p A pointer to an object of @c element_type * @param __d A reference to a deleter. * * The deleter will be initialized with @p __d */ template<typename _Del = deleter_type, typename = _Require<is_copy_constructible<_Del>>> _GLIBCXX23_CONSTEXPR unique_ptr(pointer __p, const deleter_type& __d) noexcept : _M_t(__p, __d) { } /** Takes ownership of a pointer. * * @param __p A pointer to an object of @c element_type * @param __d An rvalue reference to a (non-reference) deleter. * * The deleter will be initialized with @p std::move(__d) */ template<typename _Del = deleter_type, typename = _Require<is_move_constructible<_Del>>> _GLIBCXX23_CONSTEXPR unique_ptr(pointer __p, __enable_if_t<!is_lvalue_reference<_Del>::value, _Del&&> __d) noexcept : _M_t(__p, std::move(__d)) { } template<typename _Del = deleter_type, typename _DelUnref = typename remove_reference<_Del>::type> _GLIBCXX23_CONSTEXPR unique_ptr(pointer, __enable_if_t<is_lvalue_reference<_Del>::value, _DelUnref&&>) = delete; /// Creates a unique_ptr that owns nothing. template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> constexpr unique_ptr(nullptr_t) noexcept : _M_t() { } // Move constructors. /// Move constructor. unique_ptr(unique_ptr&&) = default; /** @brief Converting constructor from another type * * Requires that the pointer owned by @p __u is convertible to the * type of pointer owned by this object, @p __u does not own an array, * and @p __u has a compatible deleter type. */ template<typename _Up, typename _Ep, typename = _Require< __safe_conversion_up<_Up, _Ep>, __conditional_t<is_reference<_Dp>::value, is_same<_Ep, _Dp>, is_convertible<_Ep, _Dp>>>> _GLIBCXX23_CONSTEXPR unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) { } #if _GLIBCXX_USE_DEPRECATED #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /// Converting constructor from @c auto_ptr template<typename _Up, typename = _Require< is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>> unique_ptr(auto_ptr<_Up>&& __u) noexcept; #pragma GCC diagnostic pop #endif /// Destructor, invokes the deleter if the stored pointer is not null. #if __cplusplus > 202002L && __cpp_constexpr_dynamic_alloc constexpr #endif ~unique_ptr() noexcept { static_assert(__is_invocable<deleter_type&, pointer>::value, "unique_ptr's deleter must be invocable with a pointer"); auto& __ptr = _M_t._M_ptr(); if (__ptr != nullptr) get_deleter()(std::move(__ptr)); __ptr = pointer(); } // Assignment. /** @brief Move assignment operator. * * Invokes the deleter if this object owns a pointer. */ unique_ptr& operator=(unique_ptr&&) = default; /** @brief Assignment from another type. * * @param __u The object to transfer ownership from, which owns a * convertible pointer to a non-array object. * * Invokes the deleter if this object owns a pointer. */ template<typename _Up, typename _Ep> _GLIBCXX23_CONSTEXPR typename enable_if< __and_< __safe_conversion_up<_Up, _Ep>, is_assignable<deleter_type&, _Ep&&> >::value, unique_ptr&>::type operator=(unique_ptr<_Up, _Ep>&& __u) noexcept { reset(__u.release()); get_deleter() = std::forward<_Ep>(__u.get_deleter()); return *this; } /// Reset the %unique_ptr to empty, invoking the deleter if necessary. _GLIBCXX23_CONSTEXPR unique_ptr& operator=(nullptr_t) noexcept { reset(); return *this; } // Observers. /// Dereference the stored pointer. _GLIBCXX23_CONSTEXPR typename add_lvalue_reference<element_type>::type operator*() const noexcept(noexcept(*std::declval<pointer>())) { __glibcxx_assert(get() != pointer()); return *get(); } /// Return the stored pointer. _GLIBCXX23_CONSTEXPR pointer operator->() const noexcept { _GLIBCXX_DEBUG_PEDASSERT(get() != pointer()); return get(); } /// Return the stored pointer. _GLIBCXX23_CONSTEXPR pointer get() const noexcept { return _M_t._M_ptr(); } /// Return a reference to the stored deleter. _GLIBCXX23_CONSTEXPR deleter_type& get_deleter() noexcept { return _M_t._M_deleter(); } /// Return a reference to the stored deleter. _GLIBCXX23_CONSTEXPR const deleter_type& get_deleter() const noexcept { return _M_t._M_deleter(); } /// Return @c true if the stored pointer is not null. _GLIBCXX23_CONSTEXPR explicit operator bool() const noexcept { return get() == pointer() ? false : true; } // Modifiers. /// Release ownership of any stored pointer. _GLIBCXX23_CONSTEXPR pointer release() noexcept { return _M_t.release(); } /** @brief Replace the stored pointer. * * @param __p The new pointer to store. * * The deleter will be invoked if a pointer is already owned. */ _GLIBCXX23_CONSTEXPR void reset(pointer __p = pointer()) noexcept { static_assert(__is_invocable<deleter_type&, pointer>::value, "unique_ptr's deleter must be invocable with a pointer"); _M_t.reset(std::move(__p)); } /// Exchange the pointer and deleter with another object. _GLIBCXX23_CONSTEXPR void swap(unique_ptr& __u) noexcept { static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); _M_t.swap(__u._M_t); } // Disable copy from lvalue. unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; };
示例
#include <iostream> #include <memory> int main() { int *i = new int(100); std::unique_ptr<int> p(i); std::cout<<"i="<<*p<<std::endl; return 0; }
shared_ptr
template<class T> class shared_ptr { public: typedef T element_type; // constructors: constexpr shared_ptr() noexcept; template<class Y> explicit shared_ptr(Y* p); template<class Y, class D> shared_ptr(Y* p, D d); template<class Y, class D, class A> shared_ptr(Y* p, D d, A a); template <class D> shared_ptr(nullptr_t p, D d); template <class D, class A> shared_ptr(nullptr_t p, D d, A a); template<class Y> shared_ptr(const shared_ptr<Y>& r, T *p) noexcept; shared_ptr(const shared_ptr& r) noexcept; template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept; shared_ptr(shared_ptr&& r) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept; template<class Y> explicit shared_ptr(const weak_ptr<Y>& r); template<class Y> shared_ptr(auto_ptr<Y>&& r); template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r); shared_ptr(nullptr_t) : shared_ptr() { } // destructor: ~shared_ptr(); // assignment: shared_ptr& operator=(const shared_ptr& r) noexcept; template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept; shared_ptr& operator=(shared_ptr&& r) noexcept; template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r); template<class Y> shared_ptr& operator=(auto_ptr<Y>&& r); template <class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r); // modifiers: void swap(shared_ptr& r) noexcept; void reset() noexcept; template<class Y> void reset(Y* p); template<class Y, class D> void reset(Y* p, D d); template<class Y, class D, class A> void reset(Y* p, D d, A a); // observers: T* get() const noexcept; T& operator*() const noexcept; T* operator->() const noexcept; long use_count() const noexcept; bool unique() const noexcept; explicit operator bool() const noexcept; template<class U> bool owner_before(shared_ptr<U> const& b) const; template<class U> bool owner_before(weak_ptr<U> const& b) const; };
weak_ptr
template<class T> class weak_ptr { public: typedef T element_type; // constructors constexpr weak_ptr() noexcept; template<class Y> weak_ptr(shared_ptr<Y> const& r) noexcept; weak_ptr(weak_ptr const& r) noexcept; template<class Y> weak_ptr(weak_ptr<Y> const& r) noexcept; weak_ptr(weak_ptr&& r) noexcept; // C++14 template<class Y> weak_ptr(weak_ptr<Y>&& r) noexcept; // C++14 // destructor ~weak_ptr(); // assignment weak_ptr& operator=(weak_ptr const& r) noexcept; template<class Y> weak_ptr& operator=(weak_ptr<Y> const& r) noexcept; template<class Y> weak_ptr& operator=(shared_ptr<Y> const& r) noexcept; weak_ptr& operator=(weak_ptr&& r) noexcept; // C++14 template<class Y> weak_ptr& operator=(weak_ptr<Y>&& r) noexcept; // C++14 // modifiers void swap(weak_ptr& r) noexcept; void reset() noexcept; // observers long use_count() const noexcept; bool expired() const noexcept; shared_ptr<T> lock() const noexcept; template<class U> bool owner_before(shared_ptr<U> const& b) const; template<class U> bool owner_before(weak_ptr<U> const& b) const; };
相关推荐
C++智能指针的创建 C++中的指针是很麻烦的,难以管理和释放内存。为了减少问题的出现,现在有很多技巧去减少问题的出现。智能指针是其中一种解决方案。 智能指针是一种特殊的类,它可以模拟指针的行为,但同时也...
《C++智能指针——unique_ptr智能指针详解》 智能指针是C++中用于自动管理动态分配内存的一种工具,它可以确保在适当的时候自动释放内存,从而避免内存泄漏的问题。其中,`unique_ptr`是一种特殊的智能指针,它拥有...
C++ 7种智能指针测试代码
对于需要面试C++相关岗位的文章,看完这篇文章,如果面试官再问你智能指针,我敢肯定,你一定可以侃侃而谈了~智能指针的面试题,只看这一篇就够了!相信看完这篇文章,妈妈再也不用担心面试官考我智能指针的问题啦...
**C++智能指针shared_ptr详解** C++11引入了一种新的智能指针类型——`shared_ptr`,用于管理动态分配的对象。`shared_ptr`是C++标准库中的一个关键组件,它解决了传统裸指针可能导致的内存泄漏问题。通过使用`...
智能指针是用来实现指针指向的对象的共享的。其实现的基本思想: 每次创建类的新对象时,初始化指针并将引用计数置为1; 当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数; 对一个...
在C++编程中,智能指针是一种特殊类型的对象,它表现得像常规指针,但自动管理所指向的对象的生命周期。智能指针的核心目标是防止内存泄漏,这是C++编程中一个常见的问题,尤其是在处理动态分配的内存时。内存泄漏指...
智能指针是存储指向动态分配(堆)对象指针的类, 用于生存期控制, 能够确保自动正确的销毁动态分配的对象,防止内存泄露。它的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的...
对于C++智能指针作出了简要介绍。同时整理了相关的例子帮助理解。适用人群:有一定的编程基础,工作1-3年的研发人员。能学到什么:了解C++线程安全问题的原因,以及掌握解决线程安全问题的方法。同时能够掌握一下锁...
C++智能指针详解 标题解释 "C++智能指针详解abc"这一标题表明,本文将详细介绍C++中的智能指针机制,包括其概述、原理、使用方法和结论等方面。 描述解释 "C++智能指针详解abc"这一描述表明,本文将对C++中的智能...
讲解的很清楚,将智能指针的精华所在详细说明,增加理解智能指针。
C++ 智能指针(shared_ptr/weak_ptr)源码 源码位置:gcc-6.1.0\gcc-6.1.0\libstdc++-v3\include\tr1 这里只单列shared_ptr.h文件用于分析
【C++ 智能指针详解】 C++ 智能指针是C++标准库提供的一种对象,它能够自动管理动态分配的内存,从而避免内存泄漏的问题。智能指针通过模仿原始指针的行为,同时附加了一套规则来确保在适当的时候释放内存。在C++中...
C++ 智能指针C++ 智能指针C++ 智能指针
C++ 中推出了强大的智能指针smart_ptr ,本文具体说说 shared_ptr 和 weak_ptr ,特别是 enable_shared_from_this 和 shared_from_this
C++智能指针是C++语言为解决内存管理问题,特别是防止内存泄漏而引入的一种机制。传统的C++中,程序员需要手动申请和释放内存,这可能导致内存泄漏,尤其是在复杂的程序结构中。为了解决这个问题,C++引入了智能指针...
### C++智能指针实现详解 #### 引言:智能指针在C++中的角色 在C++编程语言中,动态内存管理是一项复杂且容易出错的任务,这往往是导致运行时错误的主要原因之一。错误类型多样,包括但不限于内存泄漏、过早释放...