Effective STL 条款13

原创 2004年03月05日 13:48:00

条款13:尽量使用vector和string来代替动态分配的数组

这一刻,你决定使用new来进行动态分配,你需要肩负下列职责:

  1. 你必须确保有的人以后会delete这个分配。如果后面没有delete,你的new就会产生一个资源泄漏。
  2. 你必须确保使用了delete的正确形式。对于分配一个单独的对象,必须使用“delete”。对于分配一个数组,必须使用“delete []”。如果使用了delete的错误形式,结果会未定义。在一些平台上,程序在运行期会当掉。另一方面,它会默默地走向错误,有时候会造成资源泄漏,一些内存也随之而去。
  3. 你必须确保只delete一次。如果一个分配被删除不止一次,结果再次未定义。

职责真多,而且我不能理解为什么如果可以省心你却还要负责。感谢vector和string,用了它们就可以不像以前那么麻烦了。

无论何时,你发现你自己准备动态分配一个数组(也就是,企图写“new T[...]”),你应该首先考虑使用一个vector或一个string。(一般来说,当T是一个字符类型的时候使用string,否则使用vector,但在本条款的后面,我们会遇到一个vector<char>可能是一个合理的设计选择的情况。)vector和string消除了上面的负担,因为它们管理自己的内存。当元素添加到那些容器中时它们的内存会增长,而且当一个vector或string销毁时,它的析构函数会自动销毁容器中的元素,回收存放那些元素的内存。

另外,vector和string是羽翼丰满的序列容器,所以它们让你支配可以作用于这样的容器的整个STL算法军火库。虽然数组也可以用于STL算法,但没有提供像begin、end和size这样的成员函数,也没有内嵌像iterator、reverse_iterator或value_type那样的typedef。而且char*指针当然不能和提供了专用成员函数的string竞争。STL用的越多,越会歧视内建的数组。

如果你关心你必须继续支持的遗留代码,它们都是基于数组的,放松点,无论如何都应该使用vector和string。条款16演示了把vector和string中的数据传给需要array的API有多简单,所以整合遗留代码一般都没有问题。

坦白地说,我想到了一个(也是唯一一个)用vector或string代替动态分配数组会出现的问题,而且它只关系到string。很多string实现在后台使用了引用计数(参见条款15),一个消除了不必要的内存分配和字符拷贝的策略,而且在很多应用中可以提高性能。事实上,一般认为通过引用计数优化字符串很重要,所以C++标准委员会特别设法保证了那是一个合法的实现。

唉,一个程序员的优化就是其他人的抱怨,而且如果你在多线程环境中使用了引用计数的字符串,你可能发现避免分配和拷贝所节省下的时间都花费在后台并发控制上了。(细节请参考Sutter的文章《Optimizations That Aren't (In a Multithreaded World)》[20]。)如果你在多线程环境中使用引用计数字符串,就应该注意线程安全性支持所带来的的性能下降问题。

要知道你正在使用的string实现是否是引用计数的,通常最简单的方式是参考库的文档。因为通常认为引用计数是一种优化,制作商一般把它作为一个特性来吹捧。另一种方法是看库的string实现的源代码。我一般不推荐尝试从库源代码中得到东西,但有时候这是唯一能找出你想知道的东西的方法。如果你选择了这个方法,就要记住string是一个basic_string<char>的typedef(而wstring是basic_string<wchar_t>的typedef),所以你真正需要看的是basic_string模板。最容易检查的地方是可能的类构造函数。看看它是否在某处增加了引用计数。如果是,string就是引用计数的。如果不是,要么就是string不是引用计数,要么就是你看错了代码。呵呵。

如果你用到的string实现是引用计数的,而你想在已经确定string的引用计数支持是一个性能问题的多线程环境中运行,你至少有三个合理的选择,而且没有一个放弃了STL。第一,看看你的库实现是否可以关闭引用计数,通常是通过改变预处理变量的值。当然那是不可移植的,但使工作变得可能,值得研究。第二,寻找或开发一个不使用引用计数的string实现(或部分实现)替代品。第三,考虑使用vector<char>来代替string,vector实现不允许使用引用计数,所以隐藏的多线程性能问题不会出现了。当然,如果你选择了vector<char>,你就放弃了string的专用成员函数,但大部分功能仍然可以通过STL算法得到,所以你从一种语法切换到另一种不会失去很多功能。

所有的结果都是简单的。如果你在使用动态分配数组,你可能比需要的做更多的工作。要减轻你的负担,就使用vector或string来代替。

《Effective C++》学习笔记——条款31

《Effective C++》学习笔记——条款31:将文件间的编译依存关系降至最低
  • lx417147512
  • lx417147512
  • 2015年06月15日 13:51
  • 1362

《Effective C++》让自己习惯C++:条款1-条款4

《Effective C++》条款1到条款4。基本是总结C++的一些特点,尤其是不同于C语言的特点。...
  • KangRoger
  • KangRoger
  • 2014年12月13日 19:26
  • 2340

《Effective C++》:条款44-条款45

条款44将与参数无关的代码抽离templates 条款45运用成员函数模板接受所有兼容类型...
  • KangRoger
  • KangRoger
  • 2015年03月12日 22:01
  • 1475

【Effective STL】条款13-18学习笔记

条款13:尽量使用vector和string来代替动态分配的数组 这章没什么好说的,动态分配数组需要你new或new[]和delete或delete[],还必须搭配正确,调用次数统一。既然如此多的问题...
  • Dean_Winchester
  • Dean_Winchester
  • 2013年07月18日 15:34
  • 566

effective c++条款13-17 “以对象管理资源”之shared_ptr浅析

顾名思义,boost::shared_ptr是可以共享所有权的智能指针,首先让我们通过一个例子看看它的基本用法: #include #include #include class imple...
  • hustyangju
  • hustyangju
  • 2014年12月01日 15:48
  • 674

《Effective C++ 》学习笔记——条款13

《Effective C++ 》学习笔记——条款13:以对象管理资源
  • lx417147512
  • lx417147512
  • 2014年11月23日 22:01
  • 871

effective c++条款13-17 “以对象管理资源”之RAII浅析

RAII是指C++语言中的一个惯用法(idiom),它是“Resource Acquisition Is Initialization”的首字母缩写。中文可将其翻译为“资源获取就是初始化”。虽然从某种...
  • hustyangju
  • hustyangju
  • 2014年12月01日 15:21
  • 546

effective c++条款13-17 “以对象管理资源”之C++类型转换函数和构造函数

其实我们已经在C/C++中见到过多次标准类型数据间的转换方式了,这种形式用于在程序中将一种指定的数据转换成另一指定的类型,也即是强制转换,比如:int a = int(1.23),其作用是将1.23转...
  • hustyangju
  • hustyangju
  • 2014年12月02日 10:47
  • 678

effective c++ 条款13,16(以对象管理资源,成对使用new delete的形式相同)

问题如下: 省略号部分可能出现return语句,所以后面的delete可能不被执行,导致内存泄漏。 解决方案:使用智能指针令其自动释放资源,或者将释放功能放在析构函数中 auto_ptr ...
  • qq_30078917
  • qq_30078917
  • 2017年04月14日 11:49
  • 122

Effective C++ 条款13学习笔记:以对象管理资源

Use objects to manage resources         懈怠了几天,今天应该继续努力学习Effective C++ ,让自己每天充实起来。         资源对于我们计算...
  • wallwind
  • wallwind
  • 2011年09月17日 20:48
  • 1437
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective STL 条款13
举报原因:
原因补充:

(最多只允许输入30个字)