概念:在C++11中通过引入智能指针,不需要手动释放内存
分类:
-
std::unique_ptr
-
std::shared_ptr
-
std::weak_ptr
一、智能指针概述
智能指针是原始指针的封装,优点是会自动分配内存,不用担心潜在的内存泄漏。
只能解决一部分问题,即独占、共享所有权指针的释放、传输
没有从根本上解决C++ 内存安全问题,不加以注意依然会造成内存安全问题。
二、独占指针unique_ptr
1、概念
unique_ptr:在任何给定的时刻,只能有一个指针管理内存。
当指针超出作用域时,内存将自动释放
该类型指针不可以copy,只可以move
2、创建方式:
-
通过已有裸指针创建
-
通过new 创建
-
通过 std::make_unique 创建(推荐)
// 使用unique pointer 会更安全
Cat *c_p2 = new Cat("nnnnn");
unique_ptr <Cat> u_c_p1{c_p2}; // u_c_p1指针名
// c_p2->cat_info();
// u_c_p1->cat_info();
// // 当c_p2 改变值的时候,u_c_p1也会随着改变
// c_p2->set_cat_name("enenne");
// u_c_p1->cat_info();
/*
constructor of cat:nnnnn
cat info name:nnnnn
cat info name:nnnnn
cat info name:enenne
destructor of cat:enenne*/
cout << "----------" << endl;
//delete c_p2;
c_p2 = nullptr;
u_c_p1->cat_info();
cout << "----第二种------" << endl;
//第二种 new
unique_ptr <Cat> u_c_p3{new Cat("dd")};
u_c_p3->cat_info();
u_c_p3->set_cat_name("ooooo");
u_c_p3->cat_info();
cout << "----第san种------" << endl;
// 第三种 make
unique_ptr<Cat> u_c_p4 = make_unique<Cat>("123");
u_c_p4->cat_info();
u_c_p4->set_cat_name("pppp");
u_c_p4->cat_info();
3、使用
-
可以通过 get()获取地址
-
可以通过 → 调用成员函数
-
可以通过 * 调用 dereferencing
cout << "----get 方法------" << endl;
// 使用get方法
unique_ptr <int> u_c_1 {new int(5)};
unique_ptr <int> u_c_2 = make_unique <int>(4);
cout << "u_c_1 的地址为:" << u_c_1.get() << endl;
cout << "u_c_2 的地址为:" << u_c_2.get() << endl;
cout << *u_c_1 << endl;
三、unique_ptr 与函数调用
unique_ptr 不可以copy,值可以move
在做函数参数或是返回值中一定要注意所有权问题。
注意事项:
-
passing by value:需要用move转移内存拥有权,如果参数直接传入make_unique 语句,自动转换为move
-
passing by reference:如果设置参数为const则不能改变指向,比如reset(),reset()为智能指针清空方法
-
return by value:指向一个local object ,可以用作链式函数
void do_with_cat_pass_value(unique_ptr<Cat> c){
c->cat_info();
}
void do_with_cat_pass_refer(const unique_ptr<Cat> &c){ // 建议
c->cat_info();
c->set_cat_name("jjjjjjj");
c->cat_info();
//c.reset(); // 清空指针
}
unique_ptr<Cat> get_unique_ptr(){
unique_ptr <Cat> u = make_unique<Cat> ("9898");
return u;
}
cout << "----函数调用------" << endl;
// 独占指针与函数调用
// 1、pass by value
unique_ptr <Cat> u1 = make_unique<Cat>("dd");
do_with_cat_pass_value(move(u1)); // 必须要加move
// u1->cat_info(); 不能执行
//do_with_cat_pass_value(unique_ptr<Cat>());
// 2、pass by reference
unique_ptr <Cat> u2 = make_unique<Cat>("popo");
do_with_cat_pass_refer(u2);
cout << u2.get() << endl;
//3、返回
get_unique_ptr()->cat_info();
四、计数指针:shared_ptr
shared_ptr :计数指针又称为共享指针
与unique_ptr 不同,计数指针可以共享数据
-
shared_ptr 创建了一个计数器与类对象所指的内存相关联
-
copy 则计数器加1,销毁则计数器减一
-
qpi 为use_count()
cout << "----计数指针------" << endl;
// 计数指针 shared_ptr
// 常量类型
shared_ptr <int> s1 = make_shared<int>(6);
cout << "value:" << *s1 << endl;//value:6
cout << s1.use_count() << endl; // 1,计数器个数
// 进行copy 操作
shared_ptr<int> s2 = s1;
cout << *s2 << endl; //6
cout << s2.use_count() << endl; //2
cout << s1.use_count() << endl; //2
*s2 = 90;
cout << "s2 的值为:" << *s2 << endl;
cout << "s1 的值为:" << *s1 << endl;
shared_ptr<int> s3 = s1;
s2 = nullptr;
cout << "s3 的use count为:" <<s3.use_count() << endl; //2
cout << "s2 的use count为:" <<s2.use_count() << endl; //0
cout << "s1 的use count为:" <<s1.use_count() << endl; //2
cout << "---自定义数据类型------" << endl;
// 自定义类型
shared_ptr <Cat> ss1 = make_shared<Cat>("dsds");
cout << "cat shared_ptr use count:" << ss1.use_count() << endl;
shared_ptr <Cat> ss2 = ss1;
shared_ptr <Cat> ss3 = ss1;
cout << "cat ss1 shared_ptr use count:" << ss1.use_count() << endl; //3
cout << "cat ss2 shared_ptr use count:" << ss2.use_count() << endl; //3
cout << "cat ss3 shared_ptr use count:" << ss3.use_count() << endl; //3
ss1.reset();
cout << "cat ss1 shared_ptr use count:" << ss1.use_count() << endl; //0
cout << "cat ss2 shared_ptr use count:" << ss2.use_count() << endl; //2
cout << "cat ss3 shared_ptr use count:" << ss3.use_count() << endl; //2
cout << "---自定义数据类型------" << endl;
五、shared_ptr 与函数
-
shared by passed by value:copy ,函数内部计数器加以
-
shared_ptr passed by ref:const 表示不可改变指向
-
returning by value:链式调用
// 计数指针
void cat_by_value(shared_ptr <Cat> cat){
cout << cat->getName() << endl;
cout << "func use count :" << cat.use_count() << endl;
cat->set_cat_name("oooo");
cat->cat_info();
}
void cat_by_ferer(shared_ptr <Cat> &cat){
cout << cat->getName() << endl;
cout << "func use count :" << cat.use_count() << endl;
cat->set_cat_name("lsjf");
cat->cat_info();
}
shared_ptr <Cat> get_shared_ptr(){
shared_ptr<Cat> rePtr = make_shared<Cat>("sdfjklsadklf");
return rePtr;
}
cout << "---计数指针和函数------" << endl;
shared_ptr <Cat> sh1 = make_shared<Cat> ("jishujishu ") ;
cat_by_value(sh1);
cout << "sh1 use count :" << sh1.use_count() << endl;
sh1->cat_info();
cat_by_ferer(sh1);
sh1->cat_info();
shared_ptr<Cat> sh2 = get_shared_ptr();
sh2->cat_info();
// 链式
get_shared_ptr()->cat_info();
cout << "---计数指针和函数------" << endl;
/*
func use count :2
sh1 use count :1
*/
六、sharedptr 与 uniqueptr 的转化
-
attention:不能将sharedptr 转换成uniquestr
-
uniqueptr 可以转换成sharedptr : 通过move 方法
-
将函数返回值设为uniqueptr 是一种常见的形式,可以提高代码的复用性,可以随时改变为sharedptr
unique_ptr<Cat> get_unique_ptr(){
unique_ptr <Cat> u = make_unique<Cat> ("local cat");
return u;
}
cout << "---独占指针和计数指针的转换------" << endl;
unique_ptr <Cat> m1 = make_unique<Cat>("didi");
shared_ptr <Cat> m2 = move(m1); // 转换之后m1 指针不可用
cout << "m2 use count:"<< m2.use_count() << endl;
//返回
shared_ptr<Cat> m3 = get_unique_ptr(); // 直接将unique 指针转换成 shared 指针
if(m3){
m3->cat_info();
cout << "m3 的 use count:" << m3.use_count() << endl;
}
七、weakptr : sharedptr 的补充
1、weak_ptr :
-
不拥有 所有权
-
并不能调用 → 和 解引用 *
2、作用
如果有一个A类,其中有一个需求需要存储其他A类对象的信息,如果使用shared——ptr ,在销毁时,会遇到循环依赖问题,所以需要一个不需要拥有所有权的指针来标记该同类对象。
3、转换
weakptr 可以通过 lock()函数提升为 sharedptr (类型转换)
cout << "---weak_ptr------" << endl;
shared_ptr<Cat> w1 = make_shared<Cat>("w1");
weak_ptr w2 (w1); // weakptr 不可以单独存在,只能依靠shared指针
// w 2 可以调用use count ,但是计数器不会加1
cout << "w1 use count:" << w1.use_count() << endl;
cout << "w2 use count:" << w2.use_count() << endl;
/*
w1 use count:1
w2 use count:1*/
//w2->cat_info(); 报错,不能进行调用
//cout << *w2 << endl; 报错,不能进行接引用
shared_ptr w3 = w2.lock(); // 转换成shared_ptr
cout << "w1 use count:" << w1.use_count() << endl;
cout << "w2 use count:" << w2.use_count() << endl;
cout << "w3 use count:" << w3.use_count() << endl;
/*
w1 use count:2
w2 use count:2
w3 use count:2
*/