admin管理员组文章数量:1122927
unique
文章目录
- 前言
- 一、测试:栈
- 二、原始指针
- 三、unique_ptr
- 四、unique_ptr与函数调用
- 总结
前言
unique_ptr采用独享语义,在任何给定时刻,只能有一个指针管理内存。当指针超出作用域时,内存将自动释放,而且该类型的指针不可copy,只可以move。
一、测试:栈
在使用unique_ptr前,先用类对象对栈内存进行测试。
1.类的头文件声明如下:
#ifndef CAT_H
#define CAT_H
#include<string>
#include<iostream>
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<iostream>
#include<memory>//使用智能指针的头文件
#include"cat.h"
using namespace std;
int main(int argc, char *argv[])
{//stackCat c1("OK");c1.cat_info();{Cat c1("OK");c1.cat_info();}return 0;
}
运行结果:
结论:在栈分配的局部变量生命周期结束后自动释放
二、原始指针
1.使用原始指针构建对象
#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;
int main(int argc, char *argv[])
{//heap//raw pointerCat *c_p1=new Cat("yy");c_p1->cat_info();{Cat *c_p1=new Cat("yy");c_p1->cat_info();}cout<<"----- yz -----"<<endl;return 0;
}
运行结果:
以下用来验证局部指针释放后不影响外部指针:
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;
运行结果:
结论:在堆上分配的局部变量生命周期结束后不会自动释放,需要程序员手动释放
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
使用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;
运行结果:
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;
运行结果:
结论:第一种方法容易出现独享语义冲突的问题。
2.第二种方法 new
//第二种 用newstd::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;
运行结果:
3.第三种方法 make_unique(建议使用第三种方法)
//第三种 std::make_uniquestd::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对象
//第二种 用newstd::unique_ptr<int> u_i_p3{new int(100)};cout<<"int address:"<<u_i_p3.get()<<endl;//打印地址cout<<*u_i_p3<<endl;//第三种 std::mak_uniquestd::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与函数调用
1.passing by value
1.1需要用move来转移内存拥有权。
unique_ptr采用独享语义,不能同时存在两个指向同一个对象的指针,如果在函数调用时不使用move的话会使程序报错。
下面是使用了move后的代码:
#include<iostream>
#include<memory>
#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 valuestd::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 valuestd::unique_ptr<Cat> c1=make_unique<Cat>("ff");do_with_cat_pass_value(move(c1));do_with_cat_pass_value(make_unique<Cat>());//自动movecout<<"----- yz -----"<<endl;return 0;
运行结果:
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 refunique_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 refunique_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 refunique_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;
}
运行结果:
结论:在函数里面释放后c2地址为0;如果在函数调用里面没有释放,c2地址不为0。
2.2加const,此时不允话修改指向了
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 refunique_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;
}
运行结果:
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;
运行结果:
为什么地址返回的不一样,因为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的用法。
这是本菜看大佬视频做的笔记,参考链接:C++现代实用教程:智能指针
本文标签: unique
版权声明:本文标题:unique 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1693494771a225391.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论