zoukankan      html  css  js  c++  java
  • 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") << '
    ';
      std::cout << "u2: " << (u2?"not null":"null") << '
    ';
      std::cout << "u3: " << (u3?"not null":"null") << '
    ';
      std::cout << "u4: " << (u4?"not null":"null") << '
    ';
      std::cout << "u5: " << (u5?"not null":"null") << '
    ';
      std::cout << "u6: " << (u6?"not null":"null") << '
    ';
      std::cout << "u7: " << (u7?"not null":"null") << '
    ';
      std::cout << "u8: " << (u8?"not null":"null") << '
    ';
    
      return 0;
    }

    结果如下:

    如果直接赋值,会报错。

    2、析构函数

    // unique_ptr destructor example
    #include <iostream>
    #include <memory>
    
    int main () {
        auto deleter = [](int*p){
            delete p;
            std::cout << "[deleter called]
    ";
        };
    
        std::unique_ptr<int,decltype(deleter)> foo (new int,deleter);
    
        std::cout << "foo " << (foo?"is not":"is") << " empty
    ";
    
        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 << '
    '; else std::cout << "empty
    ";
    
        bar = std::move(foo);                       // using std::move
    
        std::cout << "foo after: ";
        if (foo) std::cout << *foo << '
    '; else std::cout << "empty
    ";
    
        std::cout << "bar: ";
        if (bar) std::cout << *bar << '
    '; else std::cout << "empty
    ";
    
        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 << '
    '; else std::cout << "(null)
    ";
    
        std::cout << "bar: ";
        if (bar) std::cout << *bar << '
    '; else std::cout << "(null)
    ";
    
        std::cout << "p: ";
        if (p) std::cout << *p << '
    '; else std::cout << "(null)
    ";
        std::cout << '
    ';
    
        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_ << "]
    ";
            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 << '
    ';
    
      up.reset (new int);       // deletes managed object, acquires new pointer
      *up=10;
      std::cout << *up << '
    ';
    
      up.reset();               // deletes managed object
    
      return 0;
    }

    输出:

  • 相关阅读:
    程序员常见的坏习惯,你躺枪了吗?
    程序员常见的坏习惯,你躺枪了吗?
    程序员常见的坏习惯,你躺枪了吗?
    ACM2037
    [Golang]字符串拼接方式的性能分析
    如果一个类同时继承的两个类都定义了某一个函数会怎样呢 | Code4Fun
    Python学习笔记(四)函数式编程
    MySql之增删改查 · YbWork's Studio
    季銮西的博客
    ActiveMQ学习总结(一)
  • 原文地址:https://www.cnblogs.com/havain/p/15498212.html
Copyright © 2011-2022 走看看