美文网首页
c++智能指针(unique_ptr)

c++智能指针(unique_ptr)

作者: arkliu | 来源:发表于2022-11-13 07:02 被阅读0次

    在c++11中通过引入只能指针的概念,使得c++程序猿不需要手动释放内存

    智能指针的分类

    • std::unique_ptr
    • std::shared_prt
    • std::weak_ptr
      注意:
      std::auto_ptr已被废弃

    unique_ptr

    • unique_ptr 在任何给定的时刻,只能由一个指针管理内存
    • 当指针超出作用域时,内存将自动释放
    • 该类型指针不可copy,只能move

    unique_ptr的三种创建方式

    • 通过已有裸指针创建

    • 通过new创建

    • 通过std::make_unique创建(推荐)

    • unique_ptr可以通过get()获取地址

    • unique_ptr实现了->与*
      即可以通过->调用成员函数
      可以通过* 调用解引用

    unique_ptr创建

    cat.h

    #ifndef CAT_H
    #define CAT_H
    #include<string>
    #include<iostream>
    using namespace std;
    class Cat {
        public:
            Cat(string name);
            Cat() = default;
            ~Cat();
    
            void cat_info()const{
                cout << "cat ino name:"<<name << endl;
            }
    
            string get_name() const {
                return name;
            }
    
            void set_name(const string &name) {
                this->name = name;
            }
    
        private:
            string name{"mimi"};
    };    
    #endif
    

    cat.cpp

    #include "cat.h"
    
    Cat::Cat(string name) :name(name) {
         cout << "constructor of cat  " << name<< endl;
    }
    
    Cat::~Cat() {
        cout << "Deconstructor of cat  " << name << endl;
    }
    
    #include <iostream>
    #include <memory>
    #include "cat.h"
    using namespace std;
    
    int main() {
        // 栈上分配
        Cat c1("ok");
        c1.cat_info();
    
        // 堆上分配,裸指针
        Cat * c_cp1 = new Cat("yy");
        c_cp1->cat_info();
        delete c_cp1;
    
        //------第一种  用已经存在的地址初始化智能指针  不推荐-----
        Cat * c_p2 = new Cat("tts");
        unique_ptr<Cat> uc_p2(c_p2);
        uc_p2->cat_info();
    
        //------第二种-----
        unique_ptr<Cat>uc_p3{new Cat("dd")};
        uc_p3->cat_info();
        uc_p3->set_name("oo");
        uc_p3->cat_info();
    
        //------第三种 c++14标准 推荐使用-----
        unique_ptr<Cat>uc_p4 = make_unique<Cat>();
        uc_p4->cat_info();
        uc_p4->set_name("oo");
        uc_p4->cat_info();
        return 0;
    }
    

    get()方法返回裸指针

    #include<iostream>
    #include<string>
    #include<memory>
    using namespace std;
    
    class Test {
    
    };
    
    int main() {
        Test* test = new Test(); // 定义原始指针test,并分配内存
        unique_ptr<Test>test_ptr(test);  // 创建智能指针test_ptr,用于管理原始指针test
        cout << "         裸指针的值:" << test << endl;
        cout << "test_ptr.get()的值:" << test_ptr.get() << endl;
        cout << "    test_ptr的地址:" << &test_ptr << endl;
        return 0;
    }
    
    image.png

    函数调用与unique_ptr

    • 值传递
      需要用std::move来转移内存的拥有权
      如果参数直接传入std::make_unique语句,自动转换为move
    void do_with_cat_pass_value(unique_ptr<Cat> c) {
        c->cat_info();
    }
    
    
    unique_ptr<Cat>uc_p1 = make_unique<Cat>("hello..");
    do_with_cat_pass_value(std::move(uc_p1));
    do_with_cat_pass_value(make_unique<Cat>("world.."));
    
    • 引用传递
      如果设置参数为const则不能改变指向
      比方说reset()
    • reset()方法为智能指针清空方法
    void do_with_cat_pass_ref(unique_ptr<Cat> &c) {
        c->set_name("hhhhhhh");
        c->cat_info();
        c.reset();
    }
    
    unique_ptr<Cat>uc_p2 = make_unique<Cat>("hello..");
    do_with_cat_pass_ref(uc_p2);
    cout << "uc_p2 address is :"<<uc_p2.get()<<endl;
    
    image.png
    • 值返回
      指向一个local object
      可以用做链式函数
    unique_ptr<Cat> get_unique_ptr() {
        unique_ptr<Cat> p_cat = make_unique<Cat>("nmnm");
        return p_cat;
    }
    
    get_unique_ptr()->cat_info();
    

    \color{red}{不支持指针的运算(+, -, ++, --)}

    用nullptr赋值给unique_ptr将释放对象

    #include <iostream>
    #include <memory>
    #include<string>
    using namespace std;
    
    class Cat {
        public:
            Cat(string name);
            Cat() = default;
            ~Cat();
    
            void cat_info()const{
                cout << "cat ino name:" << name << endl;
            }
    
            string get_name() const {
                return name;
            }
    
            void set_name(const string &name) {
                this->name = name;
            }
    
        private:
            string name{"mimi"};
    };  
    
    Cat::Cat(string name) :name(name) {
         cout << "constructor of cat  " << name<< endl;
    }
    
    Cat::~Cat() {
        cout << "Deconstructor of cat  " << name << endl;
    }
    
    int main() {
        unique_ptr<Cat> pu(new Cat("tony"));
        cout <<"赋值前:"<<endl;
        if (pu != nullptr)
        {
            cout <<"pu 不是空的"<<endl;
        }
        pu = nullptr;
        if (pu == nullptr)
        {
            cout <<"pu 是空的"<<endl;
        }
        
        return 0;
    }
    
    image.png

    release释放对原始指针的控制权

    release释放对原始指针的控制权,将unique_ptr置为空,返回裸指针

    // 函数fun1需要使用指针,但是不对这个指针负责
    void fun1(const Cat* cat_ptr) {
        cout << cat_ptr->get_name() << endl;
    }
    
    // 函数fun2需要使用指针,并且会对这个指针负责
    void fun2(const Cat* cat_ptr) {
        cout << cat_ptr->get_name() << endl;
        delete cat_ptr;
    }
    
    // 函数fun3需要使用指针,但是不对这个指针负责
    void fun3(const unique_ptr<Cat> &cat_ptr) {
        cout << cat_ptr->get_name() << endl;
    }
    
    // 函数fun4需要使用指针,并且会对这个指针负责
    void fun4(const unique_ptr<Cat> cat_ptr) {
        cout << cat_ptr->get_name() << endl;
    }
    
    int main() {
        unique_ptr<Cat> pu(new Cat("tony"));
        // fun1(pu.get());
        // fun2(pu.release());
    
        fun4(std::move(pu));
        if (pu == nullptr)
        {
            cout <<"pu 是空指针"<<endl;
        }
        return 0;
    }
    

    reset()释放对象

    pp.reset()  //释放pp对象指向的资源对象
    pp.reset(nullptr)  //释放pp对象指向的资源对象
    pp.reset(new Cat("jerry"))  //释放pp对象指向的资源对象,同时指向新对象
    

    swap() 交换两个unique_ptr的控制权

    void swap(unique_ptr<T> &right);
    

    unique_ptr不是绝对安全

    unique_ptr不是绝对安全,如果程序调用exit()退出, 全局的unique_ptr可以自动释放,但是局部的unique_ptr无法释放。

    unique_ptr<Cat> pu(new Cat("全局的猫"));
    
    int main() {
        unique_ptr<Cat> pu(new Cat("局部的猫"));
        return 0;
        //exit(0);
    }
    

    此时程序结束,全局的和局部的都被释放了


    image.png

    将上面的退出方式,改为exit,局部的对象就不会被释放


    image.png

    unique_ptr支持数组

    int main() {
        // unique_ptr<Cat[]> pu(new Cat[2]);
        unique_ptr<Cat[]> pu(new Cat[2] {string("狸猫"), string("家猫")});
        cout << pu[0].get_name() << "===" << pu[1].get_name()<< endl;
        return 0;
    }
    
    image.png

    相关文章

      网友评论

          本文标题:c++智能指针(unique_ptr)

          本文链接:https://www.haomeiwen.com/subject/pjzlzrtx.html