make_shared简述
智能指针描述
unique_ptr描述
shared_ptr
shared_ptr通过get获取指向的指针!shared_ptr< A> t3 = new A;这是不可以的,这是显示的!!!不能直接赋值指针,unique_ptr同理!
分析源代码,如下代码1为简写,代码2为源码
代码1 简化版
#include<iostream>
#include<memory>
#include<vector>
using namespace std;
class countnum
{
public:
int use_count = 0;
int weak_count =0;
};
template<class T>
class _shared
{
public:
T* ptrsh;
countnum* cm;
_shared():ptrsh(0),cm(){}
~_shared()=default;
};
template<class U>
class shared:public _shared<U>
{
public:
virtual ~shared(){release();};
template<class T>
shared(T* t){
this->cm = new countnum({1,0});
this->ptrsh = t;
}
template<class T>
shared& operator=(const shared<T>& t)
{
release();
t.cm->use_count++;
this->cm = t.cm;
this->ptrsh = t.ptrsh;
return *this;
}
shared& operator=(const shared& t)
{
release();
t.cm->use_count++;
this->cm = t.cm;
this->ptrsh = t.ptrsh;
return *this;
}
shared& operator=(const shared&& t)
{
release();
// t.cm->use_count++;
this->cm = t.cm;
this->ptrsh = t.ptrsh;
return *this;
}
template<class T>
shared(const shared<T>& t)
{
t.cm->use_count++;
this->cm = t.cm;
this->ptrsh = t.ptrsh;
}
shared(const shared&& t)
{
release();
this->cm = new countnum({1,0});
this->ptrsh = t.ptrsh;
}
void release()
{
this->cm->use_count--;
if(this->cm->use_count==0)
{
delete this->ptrsh;
}
}
};
class A
{
public:
int i;
A(int a = 10):i(a){}
void fun(){cout<<"hello"<<endl;}
};
class B:public A
{
};
int main()
{
shared<A> sh(new B);
shared<A> sh1(new B);
shared<A> sh2(new B);
shared<A> sh3(new A);
sh = sh1 =sh2;
sh = shared<A>(new B);
sh = sh3;
shared<B> sh4(new B);
shared<A> t4=sh4;
shared_ptr<int> t1(new int);
shared_ptr<int> t2 = t1;
shared_ptr<A> t3 (new A);
t3.get()->fun();
t3->fun();
return 0;
}
代码2源码分析
值得注意的是,除了如下是不支持隐式转换外,其他均可隐式转换!!!
template<typename _Yp, typename = _Constructible<_Yp*>>
explicit
shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{
template<typename... _Args>
using _Constructible = typename enable_if<
is_constructible<__shared_ptr<_Tp>, _Args...>::value
>::type;
template<typename _Arg>
using _Assignable = typename enable_if<
is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr&
>::type;
public:
using element_type = typename __shared_ptr<_Tp>::element_type;
#if __cplusplus > 201402L
# define __cpp_lib_shared_ptr_weak_type 201606
using weak_type = weak_ptr<_Tp>;
#endif
/**
* @brief Construct an empty %shared_ptr.
* @post use_count()==0 && get()==0
*/
constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { }
shared_ptr(const shared_ptr&) noexcept = default;
/**
* @brief Construct a %shared_ptr that owns the pointer @a __p.
* @param __p A pointer that is convertible to element_type*.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @c delete @a __p is called.
*/
template<typename _Yp, typename = _Constructible<_Yp*>>
explicit
shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
/**
* @brief Construct a %shared_ptr that owns the pointer @a __p
* and the deleter @a __d.
* @param __p A pointer.
* @param __d A deleter.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw
*
* __shared_ptr will release __p by calling __d(__p)
*/
template<typename _Yp, typename _Deleter,
typename = _Constructible<_Yp*, _Deleter>>
shared_ptr(_Yp* __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, std::move(__d)) { }
/**
* @brief Construct a %shared_ptr that owns a null pointer
* and the deleter @a __d.
* @param __p A null pointer constant.
* @param __d A deleter.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw
*
* The last owner will call __d(__p)
*/
template<typename _Deleter>
shared_ptr(nullptr_t __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, std::move(__d)) { }
/**
* @brief Construct a %shared_ptr that owns the pointer @a __p
* and the deleter @a __d.
* @param __p A pointer.
* @param __d A deleter.
* @param __a An allocator.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw _Alloc's copy constructor and destructor must not
* throw.
*
* __shared_ptr will release __p by calling __d(__p)
*/
template<typename _Yp, typename _Deleter, typename _Alloc,
typename = _Constructible<_Yp*, _Deleter, _Alloc>>
shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
/**
* @brief Construct a %shared_ptr that owns a null pointer
* and the deleter @a __d.
* @param __p A null pointer constant.
* @param __d A deleter.
* @param __a An allocator.
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @a __d(__p) is called.
*
* Requirements: _Deleter's copy constructor and destructor must
* not throw _Alloc's copy constructor and destructor must not
* throw.
*
* The last owner will call __d(__p)
*/
template<typename _Deleter, typename _Alloc>
shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
// Aliasing constructor
/**
* @brief Constructs a %shared_ptr instance that stores @a __p
* and shares ownership with @a __r.
* @param __r A %shared_ptr.
* @param __p A pointer that will remain valid while @a *__r is valid.
* @post get() == __p && use_count() == __r.use_count()
*
* This can be used to construct a @c shared_ptr to a sub-object
* of an object managed by an existing @c shared_ptr.
*
* @code
* shared_ptr< pair<int,int> > pii(new pair<int,int>());
* shared_ptr<int> pi(pii, &pii->first);
* assert(pii.use_count() == 2);
* @endcode
*/
template<typename _Yp>
shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(__r, __p) { }
/**
* @brief If @a __r is empty, constructs an empty %shared_ptr;
* otherwise construct a %shared_ptr that shares ownership
* with @a __r.
* @param __r A %shared_ptr.
* @post get() == __r.get() && use_count() == __r.use_count()
*/
template<typename _Yp,
typename = _Constructible<const shared_ptr<_Yp>&>>
shared_ptr(const shared_ptr<_Yp>& __r) noexcept
: __shared_ptr<_Tp>(__r) { }
/**
* @brief Move-constructs a %shared_ptr instance from @a __r.
* @param __r A %shared_ptr rvalue.
* @post *this contains the old value of @a __r, @a __r is empty.
*/
shared_ptr(shared_ptr&& __r) noexcept
: __shared_ptr<_Tp>(std::move(__r)) { }
/**
* @brief Move-constructs a %shared_ptr instance from @a __r.
* @param __r A %shared_ptr rvalue.
* @post *this contains the old value of @a __r, @a __r is empty.
*/
template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>>
shared_ptr(shared_ptr<_Yp>&& __r) noexcept
: __shared_ptr<_Tp>(std::move(__r)) { }
/**
* @brief Constructs a %shared_ptr that shares ownership with @a __r
* and stores a copy of the pointer stored in @a __r.
* @param __r A weak_ptr.
* @post use_count() == __r.use_count()
* @throw bad_weak_ptr when __r.expired(),
* in which case the constructor has no effect.
*/
template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
explicit shared_ptr(const weak_ptr<_Yp>& __r)
: __shared_ptr<_Tp>(__r) { }
#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>>
shared_ptr(auto_ptr<_Yp>&& __r);
#pragma GCC diagnostic pop
#endif
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2399. shared_ptr's constructor from unique_ptr should be constrained
template<typename _Yp, typename _Del,
typename = _Constructible<unique_ptr<_Yp, _Del>>>
shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: __shared_ptr<_Tp>(std::move(__r)) { }
#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED
// This non-standard constructor exists to support conversions that
// were possible in C++11 and C++14 but are ill-formed in C++17.
// If an exception is thrown this constructor has no effect.
template<typename _Yp, typename _Del,
_Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0>
shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { }
#endif
/**
* @brief Construct an empty %shared_ptr.
* @post use_count() == 0 && get() == nullptr
*/
constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
shared_ptr& operator=(const shared_ptr&) noexcept = default;
template<typename _Yp>
_Assignable<const shared_ptr<_Yp>&>
operator=(const shared_ptr<_Yp>& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(__r);
return *this;
}
#if _GLIBCXX_USE_DEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
template<typename _Yp>
_Assignable<auto_ptr<_Yp>>
operator=(auto_ptr<_Yp>&& __r)
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}
#pragma GCC diagnostic pop
#endif
shared_ptr&
operator=(shared_ptr&& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}
template<class _Yp>
_Assignable<shared_ptr<_Yp>>
operator=(shared_ptr<_Yp>&& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}
template<typename _Yp, typename _Del>
_Assignable<unique_ptr<_Yp, _Del>>
operator=(unique_ptr<_Yp, _Del>&& __r)
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}
unique_ptr
unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。源码见最后
unique_ptr具有->和*运算符重载符,因此它可以像普通指针一样使用。
注意unique_ptr与shared_ptr一样,都不能直接赋值指针
// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
#include <iostream>
#include <memory>
struct Task {
int mId;
Task(int id ) :mId(id) {
std::cout << "Task::Constructor" << std::endl;
}
~Task() {
std::cout << "Task::Destructor" << std::endl;
}
};
int main()
{
// 通过原始指针创建 unique_ptr 实例
std::unique_ptr<Task> taskPtr(new Task(23));
//通过 unique_ptr 访问其成员
int id = taskPtr->mId;
std::cout << id << std::endl;
return 0;
}
unique_ptr 独享所有权
unique_ptr对象始终是关联的原始指针的唯一所有者。我们无法复制unique_ptr对象,它只能移动move。
由于每个unique_ptr对象都是原始指针的唯一所有者,因此在其析构函数中它直接删除关联的指针,不需要任何参考计数。
std::unique_ptr<int> ptr1;
// 方法1
if(!ptr1)
std::cout<<"ptr1 is empty"<<std::endl;
// 方法2
if(ptr1 == nullptr)
std::cout<<"ptr1 is empty"<<std::endl;
std::unique_ptr<Task> taskPtr(new Task(22));
// std::unique_ptr<Task> taskPtr2 = new Task(); // 编译错误
std::unique_ptr<Task> taskPtr = std::make_unique<Task>(34);//可以使用make_unique
Task *p1 = taskPtr.get();
taskPtr.reset(); //在 unique_ptr 对象上调用reset()函数将重置它,即它将释放delete关联的原始指针并使unique_ptr 对象为空。
unique_ptr 对象不可复制
// 编译错误 : unique_ptr 不能复制
std::unique_ptr<Task> taskPtr3 = taskPtr2; // Compile error
// 编译错误 : unique_ptr 不能复制
taskPtr = taskPtr2; //compile error
// 通过原始指针创建 taskPtr2
std::unique_ptr<Task> taskPtr2(new Task(55));
// 把taskPtr2中关联指针的所有权转移给taskPtr4
std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2); //重点move掉
// 现在taskPtr2关联的指针为空
if(taskPtr2 == nullptr)
std::cout<<"taskPtr2 is empty"<<std::endl;
// taskPtr2关联指针的所有权现在转移到了taskPtr4中
if(taskPtr4 != nullptr)
std::cout<<"taskPtr4 is not empty"<<std::endl;
// 会输出55
std::cout<< taskPtr4->mId << std::endl;
unique_ptr源码
强调!!!
// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr
{
template <class _Up>
using _DeleterConstraint =
typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
__uniq_ptr_impl<_Tp, _Dp> _M_t;
public:
using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
using element_type = _Tp;
using deleter_type = _Dp;
// 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>>,
__or_<__and_<is_reference<deleter_type>,
is_same<deleter_type, _Ep>>,
__and_<__not_<is_reference<deleter_type>>,
is_convertible<_Ep, deleter_type>>
>
>;
// Constructors.
/// Default constructor, creates a unique_ptr that owns nothing.
template <typename _Up = _Dp,
typename = _DeleterConstraint<_Up>>
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 _Up = _Dp,
typename = _DeleterConstraint<_Up>>
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
*/
unique_ptr(pointer __p,
typename conditional<is_reference<deleter_type>::value,
deleter_type, const deleter_type&>::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 deleter.
*
* The deleter will be initialized with @p std::move(__d)
*/
unique_ptr(pointer __p,
typename remove_reference<deleter_type>::type&& __d) noexcept
: _M_t(std::move(__p), std::move(__d))
{ static_assert(!std::is_reference<deleter_type>::value,
"rvalue deleter bound to reference"); }
/// Creates a unique_ptr that owns nothing.
template <typename _Up = _Dp,
typename = _DeleterConstraint<_Up>>
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
// Move constructors.
/// Move constructor.
unique_ptr(unique_ptr&& __u) noexcept
: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }
/** @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>,
typename conditional<is_reference<_Dp>::value,
is_same<_Ep, _Dp>,
is_convertible<_Ep, _Dp>>::type>>
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.
~unique_ptr() noexcept
{
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(__ptr);
__ptr = pointer();
}
// Assignment.
/** @brief Move assignment operator.
*
* @param __u The object to transfer ownership from.
*
* Invokes the deleter first if this object owns a pointer.
*/
unique_ptr&
operator=(unique_ptr&& __u) noexcept
{
reset(__u.release());
get_deleter() = std::forward<deleter_type>(__u.get_deleter());
return *this;
}
/** @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 first if this object owns a pointer.
*/
template<typename _Up, typename _Ep>
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.
unique_ptr&
operator=(nullptr_t) noexcept
{
reset();
return *this;
}
// Observers.
/// Dereference the stored pointer.
typename add_lvalue_reference<element_type>::type
operator*() const
{
__glibcxx_assert(get() != pointer());
return *get();
}
/// Return the stored pointer.
pointer
operator->() const noexcept
{
_GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
return get();
}
/// Return the stored pointer.
pointer
get() const noexcept
{ return _M_t._M_ptr(); }
/// Return a reference to the stored deleter.
deleter_type&
get_deleter() noexcept
{ return _M_t._M_deleter(); }
/// Return a reference to the stored deleter.
const deleter_type&
get_deleter() const noexcept
{ return _M_t._M_deleter(); }
/// Return @c true if the stored pointer is not null.
explicit operator bool() const noexcept
{ return get() == pointer() ? false : true; }
/
易错点
Derived* ddr = new Derived();
//up.reset(d);
unique_ptr<Base> pbase(ddr);
vector<unique_ptr<Base>> BBR;
BBR.push_back(pbase);//error,应该是BBR.push_back(move(pbase));