赞
踩
- shared_ptr<string> p1; //指向string
- shared_ptr<list<int>> p2;//指向int的list
-
- if(p1 && p1->empty())
- *p1="h1";
shared_ptr类的默认初始化:
- 如果不初始化一个shared_ptr类对象,那么该对象默认初始化为一个空指针
- //指向一个值为42的int的shared_ptr
- shared_ptr<int> p = make_shared<int>(42);
-
- //p2指向一个值为10个'9'的string
- shared_ptr<string> p2=make_shared<string>(10, '9');
-
- //p3指向一个值初始化为0的int数
- shared_ptr<int> p3 = make_shared<int>();
auto p=make_shared<vector<string>>();
- auto p=make_shared<int>(42); //p指向一个引用者
- auto q(p); //用p初始化q,那么p所指的对象计数器加1
auto r=make_shared<int>(42); r=q;
- 将q赋值给r,那么:
- r原来所指的对象引用计数变为0,然后自动释放内存
- q所指的对象的引用计数+1
演示案例:
- 首先我们定义下面的函数返回一个指向于一个值的share_ptr指针
shared_ptr<Foo> factory(T arg) { return make_share<Foo>(arg);//返回一个share_ptr类型的智能指针 }
- 情景一:例如下面函数调用factory函数来生成一个shared_ptr指针,但是p一旦离开了作用域(use_factory函数),那么p指针就失效了,因此p所指向的内存地址也就自动释放了
//函数结束之后,p就自动释放它所指向的对象的内存 void use_factory(T arg) { shared_ptr<Foo> p=factory(arg); }
- 情景二:下面的函数也是 factory函数来生成一个shared_ptr指针,但是p指针通过返回值返回了,所以,如果有另一个shared_ptr指针调用了该函数,那么该p所指向的内存地址不会随着use_factory函数的调用而释放
auto use_factory(T arg) { shared_ptr<Foo> p=factory(arg); return p; }
使用规则:
- ①我们可以使用将shared_ptr类对象指向一个new所申请的动态内存
- ②new申请的动态内存的使用、释放等规则仍然符合shared_ptr类的使用规则
使用语法:
- 因为智能指针的构造函数是explicit的。因此:我们不能将一个内置指针隐式地转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针
shared_ptr<int> p=new int(1024); //错误 shared_ptr<int> p2(new int(1024)); //正确:使用直接初始化
- 动态内存作为返回值时的使用手法:限于上面的使用语法,一个返回shared_ptr的函数不能在其返回语句中隐式转换为一个普通指针
shared_ptr<int> clone(int p) { return new int(p); //错误 } shared_ptr<int> clone(int p) { return shared_ptr<int>(new int(p)); //正确 }
- void process(shared_ptr<int> ptr){ ... }
-
- shared_ptr<int> p(new int(42)); //初始化一个智能指针对象p
- process(p); //p所指的对象引用计数加1
- //process函数调用之后,p所指的引用计数减1
- int i=*p; //正确
函数参数使用时与new的关系:
- 因为shared_ptr类会在生存周期结束之后,将引用计数减1,当引用计数为0时,会释放内存空间
- 下面是一个特殊的应用场景,需要注意
void process(shared_ptr<int> ptr){ ... } int *x(new int(1024)); process(x); //错误,不能将int*转换为一个shared_ptr<int> process(shared_ptr<int>(x)); //合法的,但是process函数返回之后内存会被释放 int j=*x; //错误,x所指的内存已经被释放了
- shared_ptr<int> p(new int(42)); //引用计数变为1
- int *q=p.get(); //正确:使用q需要注意,不要让它管理的指针被释放
-
- {//新语句块
- shared_ptr<int>(q); //用q初始化一个智能指针对象
- } //语句块结束之后,智能指针对象释放它所指的内存空间
-
- int foo=*p;//错误的,p所指的内存已经被释放了
- shared_ptr<int> p;
-
- p=new int(1024); //错误:不能将一个指针赋予shared_ptr
- p=reset(new int(1034)); //正确,p指向一个新对象
- reset函数与unqie函数配合使用:在改变对象之前,检查自己是否为当前对象的唯一用户
shared_ptr<string> p=make_shared<string>("Hello"); if(!p.unique()) //p所指向的对象还有别的智能指针所指 p.reset(new string(*p)); //现在可以放心的改变p了 *p+=newVal; //p所指向的对象只有自己一个智能指针,现在可以放心的改变对象的值了
- 当程序发生异常时,我们可以捕获异常来将资源被正确的释放。但是如果没有对异常进行处理,则有以下规则:
- shared_ptr的异常处理:如果程序发生异常,并且过早的结束了,那么智能指针也能确保在内存不再需要时将其释放
- new的异常处理:如果释放内存在异常终止之后,那么就造成内存浪费
- voif func()
- {
- shared_ptr<int> sp(new int(42));
- ...//此时抛出异常,未捕获,函数终止
- }//shared_ptr仍然会自动释放内存
- voif func()
- {
- int *ip=new int(42);
- ...//此时抛出异常,未捕获
- delete ip; //在退出之前释放内存,此语句没有执行到,导致内存浪费
- }
演示案例:
- 下面演示一个shared_ptr指定删除器函数以及避免内存泄露的案例
- 错误情景:我们调用f函数来打开一个网络连接,但是在f函数调用之后没有关闭这个连接。因此就会造成内存的泄露
struct destination; //连接的对象 struct connection; //连接需要的信息 connection connect(destbination*); //打开连接 void disconnect(connection); //关闭连接 void f(destination &d) { connection c=connect(&d);//打开一个连接 ....//使用这个连接 //如果在f函数退出之前忘记调用disconnect函数,那么该连接就没有关闭 }
- 正确情景:现在我们定义一个新的函数“end_connection”,并且配合shared_ptr类的使用。shared_ptr指定了一个删除器函数“end_connection”。因此下面的代码能够保证在f函数的各种调用结束时,保证连接正确的关闭
void end_connection(connection *p) { disconnection (*p); } void f(destination &d) { connection c=connect(&d); shared_ptr<connection> p(&c,end_connection); ....//使用这个连接 //当f函数退出或者异常退出,p都会调用end_connection函数 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。