C++笔记——unique_ptr智能指针

背景:在C++中,动态内存的管理通常是通过一对运算符new,在动态内存中为对象分配空间并返回该对象的指针,可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。在使用中容易出现问题,因为要保证在正确的时间释放内存是困难的。忘记释放会造成内存泄露。为了更安全的使用动态内存,C++11标准库提供两种智能指针来管理动态对象,shared_ptr和unique_ptr。

std::unique_ptr是C++11标准中用来取代std::auto_ptr的指针容器(在C++11中,auto_ptr被废弃)。它不能与其它unique_ptr类型的指针对象共享所指对象的内存。这种”所有权”仅能够通过标准库的move函数来转移。unique_ptr是一个删除了拷贝构造函数、保留了移动构造函数的指针封装类型。不支持普通的拷贝或赋值操作。

 

范例程序:

1、构造函数

// 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;
}

结果如下:

如果直接赋值,会报错。

 

2、析构函数

// 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]
}

输出:

 

 注意:是return0之后,deleter被调用。

 

3、赋值运算法

// 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

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

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

    std::cout << "foo after: ";
    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;
}

输出

 

 注意:这里就能体现出unique的特点,只能指向一个对象,赋值用移动构造函数std::move()

 

4、get和release方法:get函数不会使unique_ptr释放指针的所有权(即,它仍然负责在某个时刻删除托管数据)。因此,该函数返回的值不应用于构造新的托管指针。

为了获得存储的指针并释放对其的所有权,请改为调用unique_ptr::release

 

// 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;
}

 

5、get_deleter方法

// 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;
}

输出:

 

 

6、reset方法

// 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;
}

输出:

 

posted @ 2021-11-02 11:58  水水滴答  阅读(167)  评论(0编辑  收藏  举报