shared_ptr
动态的应用场景
- 程序不知道自己需要使用多少对象
- 程序不知道对象的准确类型
- 程序需要在多个对象间共享数据
不推荐使用new,delete直接管理内存
- 忘记释放内存
- 使用已经释放掉的内存
- 同一块内存释放两次
ps:想象一下,如果new 出对象在delete前的操作中,程序崩溃,该段内存必然会泄漏….
初始化一个智能指针
///使用new初始化(直接初始化)
shared_ptr<int> p1 (new int(1024));
///工厂函数使用
shared_ptr<int> clone (int p){
return shared_ptr<int> p2 (new int(p));
}
简单用法
shared_ptr<int> p1 (new int(1024));
///当前引用计数
p1.use_count();
///判断p1是否是独占状态即(引用数为1)(函数已经弃用?)
p1.unique();
///q是重新绑定的指针,d是传递的删除器,将调用d来删除,若无该两个参数,且p1独占指向的对象,则释放内存。
p1.reset(q,d);
///交换指针 p1 和 q 交换指针
p1.swap(q);
///定义的时候就自带删除器
shared_ptr<T> p2 (new int(*p1),d);
///转换成智能指针
auto p2 = make_shared<int>(42);
不要使用get()对另一个智能指针赋值,或初始化。
get得到的指针单独计数,当和它指向同一块内存区的智能指针销毁后,它将变得无效。
reset用于更新引用计数(动态绑定),需要时释放p指向的对象
实例
#include <iostream>
#include <memory>
#include <string>
using namespace std;
int main() {
//shared_ptr<int> p1 (new int(1024));
shared_ptr<string> p(new string("helloworld"));
string *q = p.get();
cout<<"引用次数"<<p.use_count()<<endl;
shared_ptr<string> p1 = p;
cout<<"引用次数"<<p.use_count()<<endl;
[&p]{
if(!p.unique()){
p.reset(new string(*p));
cout<<"引用次数"<<p.use_count()<<endl;
cout<<"reset"<<endl;
}
*p += "111";
}();
cout<<"引用次数"<<p1.use_count()<<endl;
cout<<*q<<endl;
std::cout << *p<<endl;
std::cout<< *p1;
}
运行结果
引用次数1
引用次数2
引用次数1
reset
引用次数1
helloworld
helloworld111
helloworld
说明
从结果可知,在lambda函数前p的引用达到2次,
但reset后变为1次,原因是p在reset时动态绑定,指向了新的对象,只剩p1指向原对象,而现在的p和p1,q都指向不同的内存因而,计数都为1.
注意
get()得到的q指针是一个独立计数的指针,虽然也和p1一样指向原先q所占用的那块内存。
智能指针陷阱
- 不使用相同的内置指针初始化(或reset)多个智能指针。
- 不delete get()返回的指针。
- 不使用get()初始化或reset另一智能指针
- get得到的指针单独计数,当和它指向同一块内存区的智能指针销毁后,它将变得无效。
- 如果你使用智能指针管理的资源不是new分配的内存,记得传递给他一个删除器(
示例如下
)
网络编程中的断开连接实例
void process(destination &d ){
///创建一个连接对象
connection c = connect(&d);
///为保证连接在f退出或异常退出时正常关闭connection (传递了一个删除器end_connection)
shared_ptr<connection> p_connection(&c , end_connection);
}
///退出函数在p销毁时调用end_connection()
void end_connection( connection *p){
p->disconnect(*p);
}
unique_ptr ( auto_ptr的完善版 )
简单用法
///提供了删除器但声明时的形式不同
unique_ptr<T,D> u1;
unique_ptr<T,D> u2(d);
///将u1置空,返回指针控制权
u1.release();
///注意,unique_ptr不能被拷贝或赋值!!只能接收控制权。
实例
#include <iostream>
#include <memory>
#include <string>
using namespace std;
int main() {
///通过传递指针控制权,我们可以初始化其他的智能指针
unique_ptr<string> p1(new string("hello"));
string strx = "world";
///p1放弃对指针的控制权,转给p2
unique_ptr<string> p2(p1.release());
cout << "p2: " << *p2 << endl;
unique_ptr<string> p3(new string("goodbye"));
cout << "p3: " << *p3 << endl;
///p3放弃对指针的控制权,转给p2,通过动态绑定。
p2.reset(p3.release());
cout << "p2: " << *p2 << endl;
///需要负责扫尾工作(向unique_str传递删除器,如果不传递会调用default_delete来删除)
unique_ptr<string,default_delete<string>> p_end(p2.release(),default_delete<string>());
}
weak_ptr
简单用法
///和shared_ptr sp指向同一对象,但他只是弱共享。不会影响sp的引用计数
weak_ptr<T> w(sp);
w = sp;
///expired如果use_count()等于0,返回true,否则false,用于检测共享对象是否存在。
w.expired();
///若共享对象还存在,则返回一个可使用的shared_ptr,增加引用计数。
w.lock();
weak_ptr像是为了修补无法预计的get准备的。
实例
#include <iostream>
#include <memory>
#include <string>
using namespace std;
int main() {
///为sp1创建一个弱共享wp
shared_ptr<string> sp1(new string("hello"));
weak_ptr<string> wp(sp1);
///释放sp1的内存
sp1.reset();
///若lock成功则可以使用temp1,失败则temp1为空,无法使用
if(shared_ptr<string> temp1 = wp.lock())
cout<<*temp1<<endl;
}
参考
- 《c++ Primer第五版》十二章 动态内存
- http://zh.cppreference.com/w/