Smart Pointers
tips: vs raw pointers? is smart?
unique_ptr
single pointer template
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr
arrays template
template<typename _Tp, typename _Dp>
class unique_ptr<_Tp[], _Dp>
no deleter ctor
template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
explicit
unique_ptr(pointer __p) noexcept
: _M_t(__p)
{ }
__uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
lvalue deleter ctor
template<typename _Del = deleter_type,
typename = _Require<is_copy_constructible<_Del>>>
unique_ptr(pointer __p, const deleter_type& __d) noexcept
: _M_t(__p, __d) { }
rvalue deleter ctor
typename = _Require<is_move_constructible<_Del>>>
unique_ptr(pointer __p,
__enable_if_t<!is_lvalue_reference<_Del>::value,
_Del&&> __d) noexcept
: _M_t(__p, std::move(__d))
{ }
template<typename _Del>
__uniq_ptr_impl(pointer __p, _Del&& __d)
: _M_t(__p, std::forward<_Del>(__d)) { }
tuple<pointer, _Dp> _M_t;
dtor
~unique_ptr()
{
auto& __ptr = _M_t._M_ptr();
if (__ptr != nullptr)
get_deleter()(__ptr);
__ptr = pointer();
}
reset
void reset(nullptr_t = nullptr) noexcept
{
reset(pointer());
}
void reset(pointer __p = pointer()) noexcept
{
static_assert(__is_invocable<deleter_type&, pointer>::value,
"unique_ptr's deleter must be invocable with a pointer");
using std::swap;
swap(_M_t._M_ptr(), __p);
if (__p != pointer())
get_deleter()(std::move(__p));
}
swap
void swap(unique_ptr& __u) noexcept
{
using std::swap;
swap(_M_t, __u._M_t);
}
get
pointer& _M_ptr() { return std::get<0>(_M_t); }
pointer _M_ptr() const { return std::get<0>(_M_t); }
pointer get() const noexcept
{
return _M_t._M_ptr();
}
no lvalue copy
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
operator == ,*, &, !=…
template<typename _Tp, typename _Dp,typename _Up, typename _Ep>
inline bool
operator==(const unique_ptr<_Tp, _Dp>& __x,
const unique_ptr<_Up, _Ep>& __y)
{
return __x.get() == __y.get();
}
pointer operator->() const noexcept
{
_GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
return get();
}
typename add_lvalue_reference<element_type>::type
operator*() const
{
__glibcxx_assert(get() != pointer());
return *get();
}
unique_ptr& operator=(unique_ptr&& __u) noexcept
{
reset(__u.release());
get_deleter() = std::forward<deleter_type>(__u.get_deleter());
return *this;
}
//创建一个指向 int 的空指针
std::unique_ptr<int> fPtr1;
std::unique_ptr<int> fPtr2(new int());
auto fPtr3 = std::make_unique<int>();
int main()
{
unique_ptr<int> pInt(new int(5));
// 转移所有权
unique_ptr<int> pInt2 = std::move(pInt);
//cout << *pInt << endl; // 出错,pInt 为空
cout << *pInt2 << endl;
unique_ptr<int> pInt3(std::move(pInt2));
}
share_ptr
ctor
constexpr __shared_ptr() noexcept
: _M_ptr(0), _M_refcount()
{ }
//shared_ptr
template<typename _Yp, typename = _SafeConv<_Yp>>
explicit __shared_ptr(_Yp* __p)
: _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
{
static_assert( !is_void<_Yp>::value, "incomplete type" );
static_assert( sizeof(_Yp) > 0, "incomplete type" );
_M_enable_shared_from_this_with(__p);
}
//shared_count
template<typename _Ptr>
__shared_count(_Ptr __p, /* is_array = */ false_type)
: __shared_count(__p)
{ }
template<typename _Ptr>
__shared_count(_Ptr __p, /* is_array = */ true_type)
: __shared_count(__p, __sp_array_delete{}, allocator<void>())
{ }
template<typename _Ptr>
explicit __shared_count(_Ptr __p) : _M_pi(0)
{
__try
{
_M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
}
__catch(...)
{
delete __p;
__throw_exception_again;
}
}
explicit _Sp_counted_ptr(_Ptr __p) noexcept
: _M_ptr(__p) { }
_Sp_counted_base() noexcept
: _M_use_count(1), _M_weak_count(1) { }
move ctor
__shared_ptr(__shared_ptr&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = 0;
}
copy ctor
__shared_ptr(const __shared_ptr&) noexcept = default;
__shared_count(const __shared_count& __r) noexcept
: _M_pi(__r._M_pi)
{
if (_M_pi != 0)
_M_pi->_M_add_ref_copy();
}
__shared_ptr& operator=(const __shared_ptr&) noexcept = default;
__shared_count& operator=(const __shared_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != _M_pi)
{
if (__tmp != 0)
__tmp->_M_add_ref_copy();
if (_M_pi != 0)
_M_pi->_M_release();
_M_pi = __tmp;
}
return *this;
}
dtor
~__shared_ptr() = default;
~__shared_count() noexcept
{
if (_M_pi != nullptr)
_M_pi->_M_release();
}
__exchange_and_add_dispatch
Adds the second argument's value to the first argument.
Returns the old value.
void _M_release() noexcept
{
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
_M_dispose();
if (_Mutex_base<_Lp>::_S_need_barriers)
{
__atomic_thread_fence (__ATOMIC_ACQ_REL);
}
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
-1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
//删除计数器
_M_destroy();
}
}
}
virtual void _M_dispose() noexcept
{
delete _M_ptr;
}
virtual void _M_dispose() noexcept
{
_M_impl._M_del()(_M_impl._M_ptr);
}
reset swap get
use_count unique
类似 size empty
上下行转换
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
static_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, static_cast<typename
_Sp::element_type*>(__r.get()));
}
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
const_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, const_cast<typename
_Sp::element_type*>(__r.get()));
}
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
if (auto* __p = dynamic_cast<typename
_Sp::element_type*>(__r.get()))
return _Sp(__r, __p);
return _Sp();
}
#if __cplusplus > 201402L
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, reinterpret_cast<typename
_Sp::element_type*>(__r.get()));
}
#endif
循环引用
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class ClassB;
class ClassA
{
public:
ClassA() { cout << "ClassA Constructor..." << endl; }
~ClassA() { cout << "ClassA Destructor..." << endl; }
shared_ptr<ClassB> pb; // 在 A 中引用 B
//weak_ptr<ClassB> pb;
};
class ClassB
{
public:
ClassB() { cout << "ClassB Constructor..." << endl; }
~ClassB() { cout << "ClassB Destructor..." << endl; }
shared_ptr<ClassA> pa; // 在 B 中引用 A
//weak_ptr<ClassB> pb;
};
int main()
{
shared_ptr<ClassA> spa = make_shared<ClassA>();
shared_ptr<ClassB> spb = make_shared<ClassB>();
spa->pb = spb;
spb->pa = spa;
std::cout << "spa use_cout:" << spa.use_count() << " spb use_cout:"
<< spb.use_count() << std::endl; //spa: 2 spb:2
}
weak_ptr
ctor
//default ctor
constexpr weak_ptr() noexcept = default;
//copy ctor
weak_ptr(const weak_ptr&) noexcept = default;
template<typename _Yp>
_Assignable<_Yp> operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r.lock().get();
_M_refcount = __r._M_refcount;
return *this;
}
__weak_count& operator=(const __weak_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != nullptr)
__tmp->_M_weak_add_ref();
if (_M_pi != nullptr)
_M_pi->_M_weak_release();
_M_pi = __tmp;
return *this;
}
//move ctor
template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>>
weak_ptr(weak_ptr<_Yp>&& __r) noexcept
: __weak_ptr<_Tp>(std::move(__r)) { }
//shared_ptr ctor
template<typename _Yp,
typename = _Constructible<const shared_ptr<_Yp>&>>
weak_ptr(const shared_ptr<_Yp>& __r) noexcept
: __weak_ptr<_Tp>(__r) { }
template<typename _Yp, typename = _Compatible<_Yp>>
__weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
{ }
__weak_count(const __shared_count<_Lp>& __r) noexcept
: _M_pi(__r._M_pi)
{
if (_M_pi != nullptr)
_M_pi->_M_weak_add_ref();
}
dtor
~__weak_ptr() = default;
~__weak_count() noexcept
{
if (_M_pi != nullptr)
_M_pi->_M_weak_release();
}
void _M_weak_release() noexcept
{
// Be race-detector-friendly. For more info see bits/c++config.
_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
{
_GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
if (_Mutex_base<_Lp>::_S_need_barriers)
{
// See _M_release(),
// destroy() must observe results of dispose()
__atomic_thread_fence (__ATOMIC_ACQ_REL);
}
_M_destroy();
}
}
reset swap use_count
expired
Equivalent to use_count() == 0. The destructor for the managed object may not yet have been
called, but this object's destruction is imminent (or may have already happened).
Return value
true if the managed object has already been deleted, false otherwise.
lock 获取指针使用权
std::shared_ptr<T> lock() const noexcept; (since C++11)
Creates a new std::shared_ptr that shares ownership of the managed object. If there is no
managed object, i.e. *this is empty, then the returned shared_ptr also is empty.
Effectively returns expired() ? shared_ptr<T>() : shared_ptr<T>(*this), executed
atomically.
void observe(std::weak_ptr<int> weak)
{
if (auto observe = weak.lock()) {
std::cout << "\tobserve() able to lock weak_ptr<>, value=" <<
*observe << "\n";
} else {
std::cout << "\tobserve() unable to lock weak_ptr<>\n";
}
}
int main()
{
std::weak_ptr<int> weak;
std::cout << "weak_ptr<> not yet initialized\n";
observe(weak);
{
auto shared = std::make_shared<int>(42);
weak = shared;
std::cout << "weak_ptr<> initialized with shared_ptr.\n";
observe(weak);
}
std::cout << "shared_ptr<> has been destructed due to scope exit.\
n";
observe(weak);
}
this 指针 && enable_shared_from_this
class Test
{
public:
std::shared_ptr<Test> GetMe()
{
return std::shared_ptr<Test>(this);
}
};
int main()
{
auto p1 = std::make_shared<Test>();
auto p2 = p1->GetMe();
Test* raw = new Test();
std::shared_ptr<Test> p3(raw);
std::shared_ptr<Test> p4(raw);
return 0;
}
class Test : public std::enable_shared_from_this<Test>
{
public:
std::shared_ptr<Test> GetMe()
{
return shared_from_this();
}
};
code
mutable weak_ptr<_Tp> _M_weak_this;
shared_ptr<_Tp> shared_from_this()
{
return shared_ptr<_Tp>(this->_M_weak_this);
}
template<typename _Tp1>
void _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const
noexcept
{
_M_weak_this._M_assign(__p, __n);
}
template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
typename enable_if<__has_esft_base<_Yp2>::value>::type
_M_enable_shared_from_this_with(_Yp* __p) noexcept
{
if (auto __base = __enable_shared_from_this_base(_M_refcount, __p))
__base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount);
}
template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
typename enable_if<!__has_esft_base<_Yp2>::value>::type
_M_enable_shared_from_this_with(_Yp*) noexcept
{ }
戳我跳转
效率
code1
for(int i = 0; i < count; ++i)
{
uint64_t* p = new uint64_t;
*p = 0;
delete p;
}
for(int i = 0; i < count; ++i)
{
auto p = std::make_unique<uint64_t>();
*p = 0;
}
for(int i = 0; i < count; ++i)
{
auto p = std::make_shared<uint64_t>();
*p = 0;
}
new_delete_debug
4500
4000
3500
3000
2500
2000
1500
1000
500
0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10 50 90 130 170 210 250 290 330 370 410 450 490 530 570 610 650 690 730 770 810 850 890 930 970
raw unique shared
new_delete_release
500
450
400
350
300
250
200
150
100
50
0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10 50 90 130 170 210 250 290 330 370 410 450 490 530 570 610 650 690 730 770 810 850 890 930 970
raw unique shared
uint64_t* p = new uint64_t;
int k = 0;
for(int i = 0; i < count; ++i)
{
uint64_t* q(nullptr);
q = p;
*q = 0;
++k;
}
auto p1 = std::make_shared<uint64_t>();
for(int i = 0; i < count; ++i)
{
auto q = p1;
*q = 0;
}
auto p2 = std::make_shared<uint64_t>();
for(int i = 0; i < count; ++i)
{
auto& q = p2;
*q = 0;
}
assign_debug
300
250
200
150
100
50
0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10 50 90 130 170 210 250 290 330 370 410 450 490 530 570 610 650 690 730 770 810 850 890 930 970
raw shared shared&
assign_release
25
20
15
10
0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10 50 90 130 170 210 250 290 330 370 410 450 490 530 570 610 650 690 730 770 810 850 890 930 970
raw shared shared&
使用场景
https://www.youtube.com/watch?v=JfmTagWcqoE&t=763s
unique_ptr
shared_ptr
weak_ptr
graph
deferred_ptr
https://github.com/hsutter/gcpp
总结
virtual dtor && dll