unique_ptr的使用


文章目录

  • 前言
  • 一、测试:栈
  • 二、原始指针
  • 三、unique_ptr
  • 四、unique_ptr与函数调用
  • 总结


前言

unique_ptr采用独享语义,在任何给定时刻,只能有一个指针管理内存。当指针超出作用域时,内存将自动释放,而且该类型的指针不可copy,只可以move。


一、测试:栈

在使用unique_ptr前,先用类对象对栈内存进行测试。
1.类的头文件声明如下:

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

2.头文件对应的cpp:

#include "cat.h"
Cat::Cat(std::string name):name(name)
{
    std::cout<<"Constructor of Cat:"<<name<<std::endl;
}
Cat::~Cat()
{
    std::cout<<"Destructor of Cat"<<std::endl;
}

3.主函数:

#include
#include//使用智能指针的头文件
#include"cat.h"
using namespace std;
int main(int argc, char *argv[])
{
    //stack
    Cat c1("OK");
    c1.cat_info();
    {
    Cat c1("OK");
    c1.cat_info();
    }
    
    return 0;
}

运行结果:
unique_ptr的使用_第1张图片

结论:在栈分配的局部变量生命周期结束后自动释放

二、原始指针

1.使用原始指针构建对象

#include
#include
#include"cat.h"
using namespace std;
int main(int argc, char *argv[])
{
     //heap
    //raw pointer
    Cat *c_p1=new Cat("yy");
    c_p1->cat_info();
    {
        Cat *c_p1=new Cat("yy");
        c_p1->cat_info();
    }
    cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
unique_ptr的使用_第2张图片
以下用来验证局部指针释放后不影响外部指针:

 Cat *c_p1=new Cat("yy");
    c_p1->cat_info();
    {
        Cat *c_p1=new Cat("yy_scope");
        c_p1->cat_info();
        delete c_p1;
    }
    delete c_p1;
    cout<<"----- yz -----"<<endl;
    return 0;

运行结果:
unique_ptr的使用_第3张图片
结论:在堆上分配的局部变量生命周期结束后不会自动释放,需要程序员手动释放
2.使用原始指针会出现安全性问题:


 Cat *c_p1=new Cat("yy");
    c_p1->cat_info();
    {
         c_p1=new Cat("yy_scope");
        c_p1->cat_info();
        delete c_p1;
    }
    delete c_p1;
    cout<<"----- yz -----"<<endl;
    return 0;

运行结果:
unique_ptr的使用_第4张图片
结论:对同一个指针指向的内存释放两遍会引起程序的崩溃

三、unique_ptr

使用unique_ptr可以避免原始指针的安全性问题,它有三种使用方法
1.第一种方法:通过已有的裸指针创建

 //unique_pointer 的三种创建方式
    //第一种
    Cat *c_p2=new Cat("yz");
    std::unique_ptr<Cat> u_c_p2{c_p2};
   // c_p2还能用吗?不能!建议销毁,否则如下,就不是独享语义了
/*-------------------------------*/
    c_p2->cat_info();
    u_c_p2->cat_info();
    c_p2->set_cat_name("ok");
    u_c_p2->cat_info();
/*-------------------------------*/
    c_p2=nullptr;
    delete c_p2;
    
    u_c_p2->cat_info();
    cout<<"----- yz -----"<<endl;
    return 0;

运行结果:
unique_ptr的使用_第5张图片

    c_p2->cat_info();
    u_c_p2->cat_info();
    c_p2->set_cat_name("ok");
    u_c_p2->cat_info();
    cout<<c_p2<<endl;
    cout<<u_c_p2.get()<<endl;

运行结果:
unique_ptr的使用_第6张图片
结论:第一种方法容易出现独享语义冲突的问题。
2.第二种方法 new

//第二种 用new
    std::unique_ptr<Cat> u_c_p3{new Cat("dd")};
    u_c_p3->cat_info();
    u_c_p3->set_cat_name("oo");
    u_c_p3->cat_info();
    cout<<"----- yz -----"<<endl;

运行结果:
unique_ptr的使用_第7张图片
3.第三种方法 make_unique(建议使用第三种方法)

    //第三种 std::make_unique
    std::unique_ptr<Cat> u_c_p4=make_unique<Cat>();
    u_c_p4->cat_info();
    u_c_p4->set_cat_name("oo");
    u_c_p4->cat_info();
    cout<<"----- yz -----"<<endl;

运行结果:
在这里插入图片描述
结论:使用智能指针后系统可以自动回收内存,避免内存泄漏问题。
4.补充:用unique指针创建int对象

 //第二种 用new
    std::unique_ptr<int> u_i_p3{new int(100)};
    cout<<"int address:"<<u_i_p3.get()<<endl;//打印地址
    cout<<*u_i_p3<<endl;

//第三种 std::mak_unique
    std::unique_ptr<int> u_i_p4=make_unique<int>(200);
    cout<<"int address:"<<u_i_p4.get()<<endl;//打印地址
    cout<<*u_i_p4<<endl;

运行结果:
unique_ptr的使用_第8张图片

四、unique_ptr与函数调用

1.passing by value
1.1需要用move来转移内存拥有权。
unique_ptr采用独享语义,不能同时存在两个指向同一个对象的指针,如果在函数调用时不使用move的话会使程序报错。
unique_ptr的使用_第9张图片下面是使用了move后的代码:

#include
#include
#include"cat.h"
using namespace std;
void do_with_cat_pass_value(std::unique_ptr<Cat> c)
{
    c->cat_info();
}
int main(int argc, char *argv[])
{
    std::unique_ptr<Cat> c1=make_unique<Cat>("ff");
    do_with_cat_pass_value(move(c1));
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
在这里插入图片描述
以下验证:对上面的代码稍作修改,用来验证使用了move后,原来的指针c1失效:

int main(int argc, char *argv[])
{
//1.pass by value
    
    std::unique_ptr<Cat> c1=make_unique<Cat>("ff");
    do_with_cat_pass_value(move(c1));
    c1->cat_info();
    cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
在这里插入图片描述
1.2如果参数直接传入std::make_unique语句,自动转换为move

int main(int argc, char *argv[])
{
//1.pass by value
    

    std::unique_ptr<Cat> c1=make_unique<Cat>("ff");
    do_with_cat_pass_value(move(c1));
    do_with_cat_pass_value(make_unique<Cat>());//自动move
    
     cout<<"----- yz -----"<<endl;
    return 0;

运行结果:
unique_ptr的使用_第10张图片
2.pass by reference(引用)
2.1没加const

void do_with_cat_pass_ref(std::unique_ptr<Cat> &c)
{
    c->set_cat_name("oo");
    c->cat_info();
    c.reset();
}
int main(int argc, char *argv[])
{
     //2.pass by ref
    unique_ptr<Cat> c2=make_unique<Cat>("f2");
    do_with_cat_pass_ref(c2);
    c2->cat_info();
    cout<<"address"<<c2.get()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
在这里插入图片描述
以下验证:在函数里边释放指针后原来指针失效。

int main(int argc, char *argv[])
{
     //2.pass by ref
    unique_ptr<Cat> c2=make_unique<Cat>("f2");
    do_with_cat_pass_ref(c2);
    //c2->cat_info();
    cout<<"address"<<c2.get()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
在这里插入图片描述

void do_with_cat_pass_ref(std::unique_ptr<Cat> &c)
{
    c->set_cat_name("oo");
    c->cat_info();
   
}
int main(int argc, char *argv[])
{
        //2.pass by ref
    unique_ptr<Cat> c2=make_unique<Cat>("f2");
    do_with_cat_pass_ref(c2);
    c2->cat_info();
    cout<<"address"<<c2.get()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
unique_ptr的使用_第11张图片
结论:在函数里面释放后c2地址为0;如果在函数调用里面没有释放,c2地址不为0。
2.2加const,此时不允话修改指向了
unique_ptr的使用_第12张图片

void do_with_cat_pass_ref(const std::unique_ptr<Cat> &c)
{
    c->set_cat_name("oo");
    c->cat_info();
    //c.reset();//不允话reset
}
int main(int argc, char *argv[])
{
        //2.pass by ref
    unique_ptr<Cat> c2=make_unique<Cat>("f2");
    do_with_cat_pass_ref(c2);
    c2->cat_info();
    cout<<"address"<<c2.get()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
unique_ptr的使用_第13张图片
3.pass by return value
指向一个local object,可以用作链式函数

std::unique_ptr<Cat> get_unique_ptr()
{
    std::unique_ptr<Cat> p_dog=std::make_unique<Cat>("Local cat");
    return p_dog;
}
int main(int argc, char *argv[])
{
     //链式
    get_unique_ptr()->cat_info();
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
在这里插入图片描述

cout<<"unique address:"<<p_dog.get()<<endl;
 cout<<"unique address:"<<&p_dog<<endl;

运行结果:
unique_ptr的使用_第14张图片
为什么地址返回的不一样,因为get返回的是指针指向的内存的地址,&返回的是指针的地址。

补充实验:

std::unique_ptr<Cat> get_unique_ptr(string name)
{
    std::unique_ptr<Cat> p_dog=std::make_unique<Cat>(name);
    cout<<"unique address:"<<p_dog.get()<<endl;
    cout<<"unique address:"<<&p_dog<<endl;
    return p_dog;
}

int main(int argc, char *argv[])
{

    //链式
    unique_ptr<Cat> p_dog1=get_unique_ptr("dog1");
    unique_ptr<Cat> p_dog2=get_unique_ptr("dog2");
    p_dog1->cat_info();
    p_dog2->cat_info();
     cout<<"----- yz -----"<<endl;
    return 0;
}

运行结果:
unique_ptr的使用_第15张图片

总结

以上就是unique_ptr的用法。
这是本菜看大佬视频做的笔记,参考链接:C++现代实用教程:智能指针

你可能感兴趣的:(c++,算法,c语言)