Effective STL——容器中所发生的对象拷贝问题
来源:互联网 发布:咪蒙语录 知乎 编辑:程序博客网 时间:2024/06/05 04:57
当你从容器中获取一个对象,或者添加一个对象时,你所加入的那个对象和所获取的那个对象都不是你原本期望的那个对象,而是他们的拷贝。
对于容器来说,拷贝是时刻发生的,比如你在vector,string,或者是deque中插入或者删除元素时,现有的元素会发生移动,这将伴随着许多拷贝操作。或是你调用排序算法时,或者rotate,reverse等操作时都会发生大量的拷贝。
你可能会对所有这些拷贝是怎么完成的感兴趣。这很简单,一个对象通过使用它的拷贝成员函数来拷贝,特
别是它的拷贝构造函数和它的拷贝赋值操作符。对于用户自定义类,比如Widget,这些函数传统上是这么声明的:
是通过简单地拷贝他们的内在比特来完成的。
也许你可能认为发生拷贝操作很正常,而且并没有什么,但是如果你在容器中使用的是一个拷贝过程很昂贵的对象,那么就连将对象放入容器这么一个简单的操作也可能成为性能的瓶颈。容器中移动越多的东西,你就会在拷贝上浪费越多的内存和时钟周期。此外,如果你有一个非传统意义的“拷贝”的对象,把这样的对象放进容器总是会导致不幸。
当然由于继承的存在,拷贝会导致分割。那就是说,如果你以基类对象建立一个容器,而你试图插入派生类对象,那么当对象(通过基类的拷贝构造函数)拷入容器的时候对象的派生部分会被删除:
象,比如,调用派生类的虚函数等,总是错的
一个使拷贝更高效、正确而且对分割问题免疫的简单的方式是建立指针的容器而不是对象的容器。也就是
说,不是建立一个Widget的容器,建立一个Widget*的容器。拷贝指针很快,它总是严密地做你希望的(指针
拷贝比特),而且当指针拷贝时没有分割。不幸的是,指针的容器有它们自己STL相关的头疼问题,防止内存泄露的问题。如果你想避免这些头疼并且仍要避开效率、正确性和分割问题,你可能会发现智能指针的容器是一个吸引人的选择。
STL进行了大量拷贝,但它通常设计为避
免不必要的对象拷贝,实际上,它也被实现为避免不必要的对象拷贝。和C和C++内建容器的行为做个对
比,下面的数组:
Widget w[maxNumWidgets]; // 建立一个大小为maxNumWidgets的Widgets数组
// 默认构造每个元素
即使我们一般只使用其中的一些或者我们立刻使用从某个地方获取(比如,一个文件)的值覆盖每个默认构
造的值,这也得构造maxNumWidgets个Widget对象。使用STL来代替数组,你可以使用一个可以在需要的时
候增长的vector:
vector<Widget> vw; // 建立一个0个Widget对象的vector
// 需要的时候可以扩展
我们也可以建立一个可以足够包含maxNumWidgets个Widget的空vector,但没有构造Widget:
vector<Widget> vw;
vw.reserve(maxNumWidgets);
和数组对比,STL容器更文明。它们只建立(通过拷贝)你需要的个数的对象,而且它们只在你指定的时候
做。是的,我们需要知道STL容器使用了拷贝,但是别忘了一个事实:比起数组它们仍然是一个进步。
对于容器来说,拷贝是时刻发生的,比如你在vector,string,或者是deque中插入或者删除元素时,现有的元素会发生移动,这将伴随着许多拷贝操作。或是你调用排序算法时,或者rotate,reverse等操作时都会发生大量的拷贝。
你可能会对所有这些拷贝是怎么完成的感兴趣。这很简单,一个对象通过使用它的拷贝成员函数来拷贝,特
别是它的拷贝构造函数和它的拷贝赋值操作符。对于用户自定义类,比如Widget,这些函数传统上是这么声明的:
class Widget {public:...Widget(const Widget&); // 拷贝构造函数Widget& operator=(const Widget&); // 拷贝赋值操作符...};如果你自己没有声明这些函数,你的编译器始终会为你声明它们。拷贝内建类型(比如int、指针等)也始终
是通过简单地拷贝他们的内在比特来完成的。
也许你可能认为发生拷贝操作很正常,而且并没有什么,但是如果你在容器中使用的是一个拷贝过程很昂贵的对象,那么就连将对象放入容器这么一个简单的操作也可能成为性能的瓶颈。容器中移动越多的东西,你就会在拷贝上浪费越多的内存和时钟周期。此外,如果你有一个非传统意义的“拷贝”的对象,把这样的对象放进容器总是会导致不幸。
当然由于继承的存在,拷贝会导致分割。那就是说,如果你以基类对象建立一个容器,而你试图插入派生类对象,那么当对象(通过基类的拷贝构造函数)拷入容器的时候对象的派生部分会被删除:
vector<Widget> vw;class SpecialWidget: // SpecialWidget从上面的Widget派生public Widget {...};SpecialWidget sw;vw.push_back(sw); // sw被当作基类对象拷入vw// 当拷贝时它的特殊部分丢失了分割问题暗示了把一个派生类对象插入基类对象的容器几乎总是错的。如果你希望结果对象表现为派生类对
象,比如,调用派生类的虚函数等,总是错的
一个使拷贝更高效、正确而且对分割问题免疫的简单的方式是建立指针的容器而不是对象的容器。也就是
说,不是建立一个Widget的容器,建立一个Widget*的容器。拷贝指针很快,它总是严密地做你希望的(指针
拷贝比特),而且当指针拷贝时没有分割。不幸的是,指针的容器有它们自己STL相关的头疼问题,防止内存泄露的问题。如果你想避免这些头疼并且仍要避开效率、正确性和分割问题,你可能会发现智能指针的容器是一个吸引人的选择。
STL进行了大量拷贝,但它通常设计为避
免不必要的对象拷贝,实际上,它也被实现为避免不必要的对象拷贝。和C和C++内建容器的行为做个对
比,下面的数组:
Widget w[maxNumWidgets]; // 建立一个大小为maxNumWidgets的Widgets数组
// 默认构造每个元素
即使我们一般只使用其中的一些或者我们立刻使用从某个地方获取(比如,一个文件)的值覆盖每个默认构
造的值,这也得构造maxNumWidgets个Widget对象。使用STL来代替数组,你可以使用一个可以在需要的时
候增长的vector:
vector<Widget> vw; // 建立一个0个Widget对象的vector
// 需要的时候可以扩展
我们也可以建立一个可以足够包含maxNumWidgets个Widget的空vector,但没有构造Widget:
vector<Widget> vw;
vw.reserve(maxNumWidgets);
和数组对比,STL容器更文明。它们只建立(通过拷贝)你需要的个数的对象,而且它们只在你指定的时候
做。是的,我们需要知道STL容器使用了拷贝,但是别忘了一个事实:比起数组它们仍然是一个进步。
- Effective STL——容器中所发生的对象拷贝问题
- effective stl:确保容器中对象副本正确而高效
- 学习Effective STL——仔细选择你的容器
- Effective STL——选择一个合适的容器
- Effective STL 重读笔记——容器
- effective STL 读书笔记——第一章:容器
- 由C++ STL的vector容器中存储的对象拷贝引起的对capacity属性 的理解
- 关于STL中string的拷贝问题
- Effective STL 第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉
- effective STL 读书笔记——第三章:关联容器
- 条款20:为指针的关联容器指定比较类型——effective STL
- 容器使用的12条军规——《Effective+STL中文版》试读
- 容器使用的12条军规——《Effective+STL中文版》
- Effective STL: 选择合适的容器
- Effective stl 第一章 容器
- Effective STL --关联容器
- Effective STL -- 容器
- 容器中对象拷贝的正确性与高效性
- GUI--JRadioButton
- 促销方式大全,思维导图,每个人都需要学会的做生意的绝招
- 千万级并发实现的秘密:内核不是解决方案,而是问题所在!
- Linphone编译过程问题及其解决方法
- 修改Myeclipse中的JSP、html模板
- Effective STL——容器中所发生的对象拷贝问题
- powerdesigner 设置唯一约束
- 企业信息化杂汤:信息化的价值(5)
- 编写一个程序,当程序输入Ctrl+C时,输出字符串“ Ctrl+C I got signal”,输入第5次时,程序退出 ,在其余时间,改程序循环打印helloworld信息
- 机器学习之K-means算法
- dp之最长有序子序列
- 在ios中实现摇一摇功能
- 淘宝装修提高转化率数据分析,你的店铺怎么装修的?
- [026] 微信公众帐号开发教程第2篇-微信公众帐号的类型(普通和会议)