0% found this document useful (0 votes)
4 views

C++ Smart Pointer

Uploaded by

mgze.wang
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

C++ Smart Pointer

Uploaded by

mgze.wang
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 30

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

You might also like