智能指針 - unique_ptr

簡介

non-specialized template <class T, class D = default_delete<T>> class unique_ptr;
array specialization template <class T, class D> class unique_ptr<T[],D>;

獲取指針的所有權,且該所有權不能共享

當 unique_ptr 被銷燬、或通過賦值操作改變了它的值、或顯式調用 unique_ptr:: reset() 函數時,它將會自動銷燬指針所指向的內存空間。所以,不能有兩個 unique_ptr 同時擁有同一個指針!

#include <iostream>
#include <memory>

int main() {
	
	int* p = new int(4);

	std::unique_ptr<int> up1 = std::unique_ptr<int>(p);
    
    // 不行!!
	std::unique_ptr<int> up2 = std::unique_ptr<int>(p);

	return 0;
}

構造

default (1) constexpr unique_ptr() noexcept;
from null pointer (2) constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}
from pointer (3) explicit unique_ptr (pointer p) noexcept;
from pointer + lvalue deleter (4) unique_ptr (pointer p, typename conditional<is_reference<D>::value,D,const D&> del) noexcept;
from pointer + rvalue deleter (5) unique_ptr (pointer p, typename remove_reference<D>::type&& del) noexcept;
move (6) unique_ptr (unique_ptr&& x) noexcept;
move-cast (7) template <class U, class E> unique_ptr (unique_ptr<U,E>&& x) noexcept;
move from auto_ptr (8) template <class U> unique_ptr (auto_ptr<U>&& x) noexcept;
copy (deleted!) (9) unique_ptr (const unique_ptr&) = delete;
// unique_ptr constructor example
#include <iostream>
#include <memory>

int main () {
  std::default_delete<int> d;
  std::unique_ptr<int> u1;
  std::unique_ptr<int> u2 (nullptr);
  std::unique_ptr<int> u3 (new int);
  std::unique_ptr<int> u4 (new int, d);
  std::unique_ptr<int> u5 (new int, std::default_delete<int>());
  std::unique_ptr<int> u6 (std::move(u5));
  std::unique_ptr<int> u7 (std::move(u6));
  std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));

  std::cout << "u1: " << (u1?"not null":"null") << '\n';
  std::cout << "u2: " << (u2?"not null":"null") << '\n';
  std::cout << "u3: " << (u3?"not null":"null") << '\n';
  std::cout << "u4: " << (u4?"not null":"null") << '\n';
  std::cout << "u5: " << (u5?"not null":"null") << '\n';
  std::cout << "u6: " << (u6?"not null":"null") << '\n';
  std::cout << "u7: " << (u7?"not null":"null") << '\n';
  std::cout << "u8: " << (u8?"not null":"null") << '\n';

  return 0;
}
u1: null
u2: null
u3: not null
u4: not null
u5: null
u6: null
u7: not null
u8: not null

賦值

move assignment (1) unique_ptr& operator= (unique_ptr&& x) noexcept;
assign null pointer (2) unique_ptr& operator= (nullptr_t) noexcept;
type-cast assignment (3) template <class U, class E> unique_ptr& operator= (unique_ptr<U,E>&& x) noexcept;
copy assignment (deleted!) (4) unique_ptr& operator= (const unique_ptr&) = delete;
// unique_ptr::operator= example
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int> foo;
  std::unique_ptr<int> bar;

  foo = std::unique_ptr<int>(new int (101));  // rvalue

  bar = std::move(foo);                       // using std::move

  std::cout << "foo: ";
  if (foo) std::cout << *foo << '\n'; else std::cout << "empty\n";

  std::cout << "bar: ";
  if (bar) std::cout << *bar << '\n'; else std::cout << "empty\n";

  return 0;
}
foo: empty
bar: 101

重置

void reset (pointer p = pointer()) noexcept;

釋放掉現有的所有權,並獲取 p 的所有權。

// unique_ptr::reset example
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int> up;  // empty

  up.reset (new int);       // takes ownership of pointer
  *up=5;
  std::cout << *up << '\n';

  up.reset (new int);       // deletes managed object, acquires new pointer
  *up=10;
  std::cout << *up << '\n';

  up.reset();               // deletes managed object

  return 0;
}
5
10

釋放

pointer release() noexcept;

釋放所有權,並置爲 nullptr ,返回其管理的指針。此操作並不會銷燬指針所指的空間。

// unique_ptr::release example
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int> auto_pointer (new int);
  int * manual_pointer;

  *auto_pointer=10;

  manual_pointer = auto_pointer.release();
  // (auto_pointer is now empty)

  std::cout << "manual_pointer points to " << *manual_pointer << '\n';

  delete manual_pointer;

  return 0;
}
manual_pointer points to 10

解引用

* 運算符 typename add_lvalue_reference<element_type>::type operator*() const;
-> 運算符 pointer operator->() const noexcept;
// unique_ptr::operator*
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int> foo (new int);
  std::unique_ptr<int> bar (new int (100));

  *foo = *bar * 2;

  std::cout << "foo: " << *foo << '\n';
  std::cout << "bar: " << *bar << '\n';

  return 0;
}
foo: 200
bar: 100
// unique_ptr::operator->
#include <iostream>
#include <memory>

struct C { int a; int b; };

int main () {
  std::unique_ptr<C> foo (new C);
  std::unique_ptr<C> bar;

  foo->a = 10;
  foo->b = 20;

  bar = std::move(foo);

  if (foo) std::cout << "foo: " << foo->a << ' ' << foo->b << '\n';
  if (bar) std::cout << "bar: " << bar->a << ' ' << bar->b << '\n';

  return 0;
}
bar: 10 20

訪問數組

element_type& operator[](size_t i) const;  // only defined in array-specialization
// unique_ptr::operator[]
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int[]> foo (new int[5]);

  for (int i=0; i<5; ++i) foo[i] = i;

  for (int i=0; i<5; ++i) std::cout << foo[i] << ' ';
  std::cout << '\n';

  return 0;
}
0 1 2 3 4 

交換

成員函數 void swap (unique_ptr& x) noexcept;
非成員函數 template <class T, class D> void swap (unique_ptr<T,D>& x, unique_ptr<T,D>& y) noexcept;
// unique_ptr::swap example
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int> foo (new int(10));
  std::unique_ptr<int> bar (new int(20));

  foo.swap(bar);

  std::cout << "foo: " << *foo << '\n';
  std::cout << "bar: " << *bar << '\n';

  return 0;
}
foo: 20
bar: 10
// unique_ptr swap specialization
#include <iostream>
#include <memory>

int main () {
  std::unique_ptr<int> foo (new int(10));
  std::unique_ptr<int> bar (new int(20));

  swap(foo,bar);

  std::cout << "foo: " << *foo << '\n';
  std::cout << "bar: " << *bar << '\n';

  return 0;
}
foo: 20
bar: 10

其他操作

獲取 stored pointer

pointer get() const noexcept;
// unique_ptr::get vs unique_ptr::release
#include <iostream>
#include <memory>

int main () {
                                           // foo   bar    p
                                           // ---   ---   ---
  std::unique_ptr<int> foo;                // null
  std::unique_ptr<int> bar;                // null  null
  int* p = nullptr;                        // null  null  null

  foo = std::unique_ptr<int>(new int(10)); // (10)  null  null
  bar = std::move(foo);                    // null  (10)  null
  p = bar.get();                           // null  (10)  (10)
  *p = 20;                                 // null  (20)  (20)
  p = nullptr;                             // null  (20)  null

  foo = std::unique_ptr<int>(new int(30)); // (30)  (20)  null
  p = foo.release();                       // null  (20)  (30)
  *p = 40;                                 // null  (20)  (40)

  std::cout << "foo: ";
  if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n";

  std::cout << "bar: ";
  if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n";

  std::cout << "p: ";
  if (p) std::cout << *p << '\n'; else std::cout << "(null)\n";
  std::cout << '\n';

  delete p;   // the program is now responsible of deleting the object pointed to by p
              // bar deletes its managed object automatically

  return 0;
}
foo: (null)
bar: 20
p: 40

獲取 stored deleter

deleter_type& get_deleter() noexcept;

const deleter_type& get_deleter() const noexcept;
// unique_ptr deleter with state
#include <iostream>
#include <memory>

class state_deleter {  // a deleter class with state
  int count_;
public:
  state_deleter() : count_(0) {}
  template <class T>
  void operator()(T* p) {
    std::cout << "[deleted #" << ++count_ << "]\n";
    delete p;
  }
};

int main () {
  state_deleter del;

  std::unique_ptr<int> p;   // uses default deleter

  // alpha and beta use independent copies of the deleter:
  std::unique_ptr<int,state_deleter> alpha (new int);
  std::unique_ptr<int,state_deleter> beta (new int,alpha.get_deleter());

  // gamma and delta share the deleter "del" (deleter type is a reference!):
  std::unique_ptr<int,state_deleter&> gamma (new int,del);
  std::unique_ptr<int,state_deleter&> delta (new int,gamma.get_deleter());

  std::cout << "resetting alpha..."; alpha.reset(new int);
  std::cout << "resetting beta..."; beta.reset(new int);
  std::cout << "resetting gamma..."; gamma.reset(new int);
  std::cout << "resetting delta..."; delta.reset(new int);

  std::cout << "calling gamma/delta deleter...";
  gamma.get_deleter()(new int);

  alpha.get_deleter() = state_deleter();  // a brand new deleter for alpha

  // additional deletions when unique_ptr objects reach out of scope
  // (in inverse order of declaration)

  return 0;
}
resetting alpha...[deleted #1]
resetting beta...[deleted #1]
resetting gamma...[deleter #1]
resetting delta...[deleter #2]
calling gamma/delta deleter...[deleted #3]
[deleted #4]
[deleted #5]
[deleted #2]
[deleter #1]

轉換爲布爾值

explicit operator bool() const noexcept;

stored pointer 爲 null -> false;不爲 null -> true 。

// example of unique_ptr::operator bool
#include <iostream>
#include <memory>


int main () {
  std::unique_ptr<int> foo;
  std::unique_ptr<int> bar (new int(12));

  if (foo) std::cout << "foo points to " << *foo << '\n';
  else std::cout << "foo is empty\n";

  if (bar) std::cout << "bar points to " << *bar << '\n';
  else std::cout << "bar is empty\n";

  return 0;
}
foo is empty
bar points to 12

關係運算符

支持 == , !=, < , <= , > , >= 。比較的是兩者的 stored pointer 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章