建议34:用智能指针管理通过new创建的对象(2)
boost::shared_ptr支持STL容器:
- typedef boost::shared_ptr<string> CStringPtr;
- std::vector< CStringPtr > strVec;
- strVec.push_back( CStringPtr(new string("Hello")) );
当vector被销毁时,其元素—智能指针对象才会被销毁,除非这个对象被其他的智能指针引用,如下面的代码片段所示:- typedef boost::shared_ptr<string> CStringPtr;
- std::vector< CStringPtr > strVec;
- strVec.push_back( CStringPtr(new string("Hello")) );
- strVec.push_back( CStringPtr(new string("Smart")) );
- strVec.push_back( CStringPtr(new string("Pointer")) );
-
- CStringPtr strPtr = strVec[0];
- strVec.clear(); //strVec清空,但是保留了strPtr引用的strVec[0]
- cout<<*strPtr<<endl; // strVec[0]依然有效
Boost智能指针同样支持数组,boost::scoped_array 和boost::shared_array对象指向的是动态配置的数组。
Boost的智能指针虽然增强了安全性,处理了潜在的危险,但是我们在使用时还是应该遵守一定的规则,以确保代码更加鲁棒。
规则1:Smart_ptr<T>不同于T*
Smart_ptr<T>的真实身份其实是一个对象,一个管理动态配置对象的对象,而T*是指向T类型对象的一个指针,所以不能盲目地将一个T*和一个智能指针类型Smart_ptr<T>相互转换。
在创建一个智能指针的时候需要明确写出Smart_ptr<T> tPtr<new T>。
禁止将T*赋值给一个智能指针。
不能采用tPtr = NULL的方式将tPtr置空,应该使用智能指针类的成员函数。
规则2:不要使用临时的 share_ptr对象
如下所示:
- class A;
- bool IsAllReady();
- void ProcessObject(boost::shared_ptr< A> pA, bool isReady);
- ProcessObject(boost::shared_ptr(new A), IsAllReady());
调用ProcessObject函数之前,C++(www.cppentry.com)编译器必须完成三件事:
(1) 执行"new A"。
(2) 调用 boost::shared_ptr的构造函数。
(3) 调用函数IsAllReady()。
因为函数参数求值顺序的不确定性,如果调用IsAllReady()发生在另外两个过程中间,而它又正好出现了异常,那么new A得到的内存返回的指针就会丢失,进而发生内存泄露,因为返回的指针没有被存入我们期望能阻止资源泄漏的boost::shared_ptr上。避免出现这种问题的方式就是不要使用临时的share_ptr对象,改用一个局部变量来实现,在一个独立的语句中将通过new 创建出来的对象存入智能指针中:
- boost::shared_ptr<A> pA(new A)
- ProcessObject(pA, IsAllReady());
如果疏忽了这一点,当异常发生时,可能会引起微妙的资源泄漏。
请记住:
时刻谨记RAII原则,使用智能指针协助我们管理动态配置的内存能给我们带来极大的便利,但是需要我们谨慎而明智地做出选择。