关闭

编写高质量代码:改善C++程序的150个建议(连载18)

发表于:2012-4-27 09:40

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:李健    来源:51Testing软件测试网采编

  Smart Pointer作为C++垃圾回收机制的核心,必须足够强大、具有工业强度,并且保证安全性。可是STL中的auto_ptr却像是扶不起的阿斗,不堪大用。在这样的情况下,C++标准委员会自然需要考虑引入新的智能指针。其中由C++标准委员会库工作组发起的Boost组织开发的Boost系列智能指针最为著名。除此之外,还有Loki库提供的SmartPtr、ATL提供的CComPtr和CComQIPtr。一个好消息是,就在2011年的9月刚刚获得通过的C++新标准C++ 11中废弃了auto_ptr指针,取而代之的是两个新的指针类:shared_ptr和unique_ptr。shared_ptr只是单纯的引用计数指针,unique_ptr是用来取代auto_ptr的。unique_ptr提供了auto_ptr的大部分特性,唯一的例外是auto_ptr的不安全、隐性的左值搬移;而unique_ptr可以存放在C++0x提出的那些能察觉搬移动作的容器之中。

  在Boost中的智能指针共有五种:scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr,其中最有用的就是shared_ptr,它采取了引用计数,并且是线程安全的,同时支持扩展,推荐在大多数情况下使用。

  boost::shared_ptr支持STL容器:

  1. typedef boost::shared_ptr<string>  CStringPtr;  
  2. std::vector< CStringPtr > strVec;  
  3. strVec.push_back( CStringPtr(new string("Hello")) );

  当vector被销毁时,其元素—智能指针对象才会被销毁,除非这个对象被其他的智能指针引用,如下面的代码片段所示:

  1. typedef boost::shared_ptr<string>  CStringPtr;  
  2. std::vector< CStringPtr > strVec;  
  3. strVec.push_back( CStringPtr(new string("Hello")) );  
  4. strVec.push_back( CStringPtr(new string("Smart")) );  
  5. strVec.push_back( CStringPtr(new string("Pointer")) );  
  6.  
  7. CStringPtr strPtr = strVec[0];  
  8. strVec.clear(); //strVec清空,但是保留了strPtr引用的strVec[0]  
  9. 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对象

  如下所示:

  1. class A;  
  2. bool IsAllReady();  
  3. void ProcessObject(boost::shared_ptr< A> pA,  bool isReady);  
  4. ProcessObject(boost::shared_ptr(new A), IsAllReady());

  调用ProcessObject函数之前,C++编译器必须完成三件事:

  (1)执行"new A"。

  (2)调用 boost::shared_ptr的构造函数。

  (3)调用函数IsAllReady()。

  因为函数参数求值顺序的不确定性,如果调用IsAllReady()发生在另外两个过程中间,而它又正好出现了异常,那么new A得到的内存返回的指针就会丢失,进而发生内存泄露,因为返回的指针没有被存入我们期望能阻止资源泄漏的boost::shared_ptr上。避免出现这种问题的方式就是不要使用临时的share_ptr对象,改用一个局部变量来实现,在一个独立的语句中将通过new 创建出来的对象存入智能指针中:

  1. boost::shared_ptr<A> pA(new A)  
  2. ProcessObject(pA, IsAllReady());

  如果疏忽了这一点,当异常发生时,可能会引起微妙的资源泄漏。

  请记住:

  时刻谨记RAII原则,使用智能指针协助我们管理动态配置的内存能给我们带来极大的便利,但是需要我们谨慎而明智地做出选择。

42/4<1234>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号