STL三十条
+ -
管理员 VIP用户 编辑
2023-10-16 0 0

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

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

你必须确保有的人以后会delete这个分配。如果后面没有delete,你的new就会产生一个资源泄漏。
你必须确保使用了delete的正确形式。对于分配一个单独的对象,必须使用“delete”。对于分配一个数组,必须使用“delete []”。如果使用了delete的错误形式,结果会未定义。在一些平台上,程序在运行期会当掉。另一方面,它会默默地走向错误,有时候会造成资源泄漏,一些内存也随之而去。
你必须确保只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来代替。

插入辅文

条款13:尽量使用vectorstring来代替动态分配的数组
这一刻,你决定使用new来进行动态分配,你需要肩负下列职责:你必须确保有的人以后会delete这个分配。如果后面没有delete,你的new就会产生一个资源泄漏。你必须确保使用了delete的正确形式。对于分配一个单独的对象,必须使用“delete”。对于分配一个数组,必须使用“delete []......
条款15:小心string实现的多样性
Bjarne Stroustrup曾经用奇特的标题写一篇文章,《Sixteen Ways to Stack a Cat》[27]。事实表明实现string几乎有和那一样多的方法。当然,作为有经验而且老于世故的软件工程师,我们应该忽视“实现细节”,但是如果爱因斯坦是对的,上帝存在于细节里,现实要求我们......
条款16: 如何将vectorstring的数据传给遗留的API
因为C++语言已经在1998年标准化,C++的中坚分子在努力推动程序员从数组转到vector时就没什么顾虑了。同样明显的情况也发生于尝试使开发者从char*指针迁移到string对象的过程中。有很好的理由来做这些转变,包括可以消除常见的编程错误(参见条款13),而且有机会获得STL算法的全部强大能力......
条款18:避免使用vector
做为一个STL容器,vector确实只有两个问题。第一,它不是一个STL容器。第二,它并不容纳bool。除此以外,就没有什么要反对的了。一个东西不能成为STL容器只因为会有人会说它是。一个东西要成为STL容器就必须满足所有在C++标准23.1节中列出的容器必要条件。在这些要......
条款23:考虑用有序vector代替关联容器
当需要一个提供快速查找的数据结构时,很多STL程序员立刻会想到标准关联容器:set、multiset、map和multimap。直到现在这很好,但不是永远都好。如果查找速度真得很重要,的确也值得考虑使用非标准的散列容器(参见条款25)。如果使用了合适的散列函数,则可以认为散列容器提供了常数时间的查找......
条款47:避免产生只写代码
假设你有一个vector,你想去掉vector中值小于x而出现在至少和y一样大的最后一个元素之后的所有元素。下面代码立刻出现在你脑中吗?vector v;int x, y;...v.erase( remove_if(find_if(v.rb......
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!