您的位置:首页 > 产品设计 > UI/UE

智能指针(smart pointer)(2):unique_ptr

2015-06-18 18:53 465 查看
Unique pointer:

  Manages the storage of a pointer, providing a limited garbage-collection facility, with little to no overhead over built-in pointers (depending on the deleter used).

   These objects have the ability of taking ownership of a pointer: once they take ownership they manage the pointed object by becoming responsible for its deletion at some point.

   unique_ptr objects automatically delete the object they manage (using a deleter) as soon as they themselves are destroyed, or as soon as their value changes either by an assignment operation or by an explicit call to unique_ptr::reset.

   unique_ptr objects own their pointer uniquely: no other facility shall take care of deleting the object, and thus no other managed pointer should point to its managed object, since as soon as they have to, unique_ptr objects delete their managed object without taking into account whether other pointers still point to the same object or not, and thus leaving any other pointers that point there as pointing to an invalid location.

   A unique_ptr object has two components:

  • a stored pointer: the pointer to the object it manages. This is set on construction, can be altered by anassignment operation or by calling member reset, and can be individually accessed for reading using members get or release.

  • a stored deleter: a callable object that takes an argument of the same type as the stored pointer and is called to delete the managed object. It is set on construction, can be altered by an assignment operation, and can be individually accessed using member get_deleter.

  unique_ptr objects replicate a limited pointer functionality by providing access to its managed object through operators * and -> (for individual objects), or operator [] (for array objects). For safety reasons, they do not support pointer arithmetics, and only support move assignment (disabling copy assignments).

  来看代码:

template <typename _Tp, typename _Tp_Deleter = default_delete<_Tp> >
class unique_ptr
{
public:
typedef _Tp*               pointer;
typedef _Tp                element_type;
typedef _Tp_Deleter        deleter_type;

// Constructors.
unique_ptr()
: _M_t(pointer(), deleter_type())
{ static_assert(!std::is_pointer<deleter_type>::value,
"constructed with null function pointer deleter"); }

explicit
unique_ptr(pointer __p)
: _M_t(__p, deleter_type())
{ static_assert(!std::is_pointer<deleter_type>::value,
"constructed with null function pointer deleter"); }

unique_ptr(pointer __p,
typename std::conditional<std::is_reference<deleter_type>::value,
deleter_type, const deleter_type&>::type __d)
: _M_t(__p, __d) { }

unique_ptr(pointer __p,
typename std::remove_reference<deleter_type>::type&& __d)
: _M_t(std::move(__p), std::move(__d))
{ static_assert(!std::is_reference<deleter_type>::value,
"rvalue deleter bound to reference"); }

// Move constructors.
unique_ptr(unique_ptr&& __u)
: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }

template<typename _Up, typename _Up_Deleter>
unique_ptr(unique_ptr<_Up, _Up_Deleter>&& __u)
: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter()))
{ }

// Destructor.
~unique_ptr() { reset(); }

// Assignment.
unique_ptr&
operator=(unique_ptr&& __u)
{
reset(__u.release());
get_deleter() = std::move(__u.get_deleter());
return *this;
}

template<typename _Up, typename _Up_Deleter>
unique_ptr&
operator=(unique_ptr<_Up, _Up_Deleter>&& __u)
{
reset(__u.release());
get_deleter() = std::move(__u.get_deleter());
return *this;
}

unique_ptr&
operator=(__unspecified_pointer_type)
{
reset();
return *this;
}

// Observers.
typename std::add_lvalue_reference<element_type>::type operator*() const
{
_GLIBCXX_DEBUG_ASSERT(get() != 0);
return *get();
}

pointer
operator->() const
{
_GLIBCXX_DEBUG_ASSERT(get() != 0);
return get();
}

pointer
get() const
{ return std::get<0>(_M_t); }

typename std::add_lvalue_reference<deleter_type>::type
get_deleter()
{ return std::get<1>(_M_t); }

typename std::add_lvalue_reference<
typename std::add_const<deleter_type>::type
>::type
get_deleter() const
{ return std::get<1>(_M_t); }

operator __unspecified_bool_type () const
{ return get() == 0 ? 0 : &unique_ptr::_M_t; }

// Modifiers.
pointer
release()
{
pointer __p = get();
std::get<0>(_M_t) = 0;
return __p;
}

void
reset(pointer __p = pointer())
{
if (__p != get())
{
get_deleter()(get());
std::get<0>(_M_t) = __p;
}
}

void
swap(unique_ptr&& __u)
{
using std::swap;
swap(_M_t, __u._M_t);
}

// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;

template<typename _Up, typename _Up_Deleter>
unique_ptr(const unique_ptr<_Up, _Up_Deleter>&) = delete;

unique_ptr& operator=(const unique_ptr&) = delete;

template<typename _Up, typename _Up_Deleter>
unique_ptr& operator=(const unique_ptr<_Up, _Up_Deleter>&) = delete;

private:
__tuple_type _M_t;
};


  上面的代码禁用了拷贝构造和赋值操作,所以在使用时必须强调使用move语义或右值引用,否则会报错。

总结:

  unique_ptr是一个独享所有权的智能指针,它提供了一种严格语义上的所有权,包括:

  1、拥有它所指向的对象。

  2、无法进行复制构造,也无法进行复制赋值操作。也就是说,我们无法得到指向同一个对象的两个unique_ptr。但是可以进行移动构造和移动赋值操作。

  3、保存指向某个对象的指针,当它本身被删除释放的时候(比如,离开了某个作用域),会使用给定的删除器释放它指向的对象。

  使用unique_ptr,可以实现以下功能,包括:

  1、为动态申请的内存提供异常安全。

  2、将动态申请内存的所有权传递给某个函数。

  3、从某个函数返回动态申请内存的所有权。

  4、在容器中保存指针。

  5、所有auto_ptr应该具有的(但无法在C++ 03中实现的)功能

  至于unique_ptr和auto_ptr区别主要是在语义上,而且在必须交换控制权的情况下(非右值),unique_ptr会显式的要求执行move操作,否则它会对用户提出警示,这避免一些无心的拷贝发生。第二个区别是unique_ptr更加的高效,因为他使用的是右值引用,而不是拷贝构造。 

  auto_ptr析构函数只是单纯的delete掉raw指针,而unique_ptr则可以定制自己的deleter,来指定unique_ptr析构时需要做哪些工作。

// unique_ptr destructor example
#include <iostream>
#include <memory>

int main () {
auto deleter = [](int*p){
delete p;
std::cout << "[deleter called]\n";
};

std::unique_ptr<int,decltype(deleter)> foo (new int,deleter);

std::cout << "foo " << (foo?"is not":"is") << " empty\n";

return 0;                        // [deleter called]
}
Output:
foo is not empty
[deleter called]


  c++11中引入的move语义使得unique_ptr可以存放到容器中,参考这篇文章(http://www.th7.cn/Program/cp/201408/267890.shtml)。使用move就表示放弃对该对象的所有权,但并不对raw指针进行释放。经过move函数调用后,失去了对raw指针的所有权,并未释放raw指针,之后如果误用了原来的unique_ptr,会导致undefine行为。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: