最近研究对象容器,稍微总结一下,以后继续补充:
当你从容器中获取一个对象,或者添加一个对象时,你所加入的那个对象和所获取的那个对象都不是你原本期望的那个对象,而是他们的拷贝。
对于容器来说,拷贝是时刻产生的,比如你在vector,string,或者是deque中插入或者删除元素时,现有的元素会产生移动,这将伴随着许多拷贝操作。或是你调用排序算法时,或者rotate,reverse等操作时都会产生大量的拷贝。 你可能会对所有这些拷贝是怎么实现的感兴趣。这很简单,一个对象通过应用它的拷贝成员函数来拷贝,特 别是它的拷贝结构函数和它的拷贝赋值操作符。对于用户自定义类,比如Widget,这些函数传统上是这么声明的:class Widget {public:...Widget(const Widget&); // 拷贝结构函数Widget& operator=(const Widget&); // 拷贝赋值操作符...};
如果你自己没有声明这些函数,你的编译器始终会为你声明它们。拷贝内建类型(比如int、指针等)也始终
是通过简单地拷贝他们的内涵比特来实现的。
也许你可能以为产生拷贝操作很正常,而且并没有什么,但是如果你在容器中应用的是一个拷贝进程很昂贵的对象,那么就连将对象放入容器这么一个简单的操作也可能成为性能的瓶颈。容器中移动越多的货色,你就会在拷贝上糟蹋越多的内存和时钟周期。此外,如果你有一个非传统意思的“拷贝”的对象,把这样的对象放进容器老是会致使可怜。
当然由于继承的存在,拷贝会致使分割。那就是说,如果你以基类对象建立一个容器,而你试图插入派生类对象,那么当对象(通过基类的拷贝结构函数)拷入容器的时候对象的派生部分会被删除:
vectorvw;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容器应用了拷贝,但是别忘了一个现实:比起数组它们仍然是一个先进。
文章结束给大家分享下程序员的一些笑话语录: 祝大家在以后的日子里. 男生象Oracle般健壮; 女生象win7般漂亮; 桃花运象IE中毒般频繁; 钱包如Gmail容量般壮大, 升职速度赶上微软打补丁 , 追女朋友像木马一样猖獗, 生活像重装电脑后一样幸福, 写程序敲代码和聊天一样有**。