主题:vector的push_back()的一个问题
lynn9
[专家分:50] 发布于 2009-01-07 23:00:00
#include<vector>
#include<iostream>
int main()
{
std::vector<Point> pointVec;
Point a;
Point b;
pointVec.push_back(a);
pointVec.push_back(b);
std::cout<<pointVec.size()<<std::endl;
return 0;
}
class Point
构造输出construction
拷贝输出copy construction
析构输出destruction
main输出结果为
construction!
construction!
copy construction!
copy construction!
copy construction!
destruction!
2
destruction!
destruction!
destruction!
destruction!
Press any key to continue
为什么会有三次拷贝出现。麻烦帮助解答一下疑问。先tks各位。
回复列表 (共6个回复)
沙发
Chipset [专家分:16190] 发布于 2009-01-08 00:10:00
我们来看看vector的增长过程。
首先开始是0,开辟一个元素的空间,放入一个对象后大小是1,然后开辟两个元素空间,复制原来的对象,再放入一个对象,销毁原来的空间(这里销毁原来的对象需要调用析构函数1次),此时大小是2。
放入两个对象需要调用拷贝构造函数2次,复制一次需要调用拷贝构造函数1次,共调用拷贝构造函数3次。
板凳
Chipset [专家分:16190] 发布于 2009-01-09 18:56:00
今天才见到本站短消息。
首先vector的大小增长过程是这样的,0 -> 1 -> 2 -> 4 -> 8 -> 16 -> 32 ...
当然了,你或许会问:为什么是2的指数次增长?这是一个数学问题,为了尽可能的减小时间复杂度,另外一种做法是每次增加固定大小,但是这种做法时间复杂度很高,速度非常慢,据我所知严的数据结构线性表就是这样增长的。如果你愿意比较,可以用数学推倒试试看看结果。
当然了,或许你还不明白,为什么要复制元素。因为在内存里分配空间,一旦分配完毕,这块空间就是固定大小,不能变了,如果希望改变只能再重新分配空间,但是需要把原来分配的空间里面存放的元素复制到新空间里面,然后释放掉原来分配的空间。你的问题很明显复制元素过程中需要调用拷贝构造函数。
vector空间动态增长是通过内存分配器alloctor(在STL头文件memory里面)分配空间来完成的,allocator是类,里面含有一些内存管理的函数。
3 楼
JackieRasy [专家分:3050] 发布于 2009-01-09 20:42:00
Chipset果然是个超级大牛,我不久前好好学习了STL,听你这么一说,我都没什么好说的了。
4 楼
Chipset [专家分:16190] 发布于 2009-01-09 21:47:00
[quote]Chipset果然是个超级大牛,我不久前好好学习了STL,听你这么一说,我都没什么好说的了。[/quote]
其实我很菜。
5 楼
xfxsworld [专家分:20] 发布于 2009-01-09 23:46:00
具体过程如下:
1. pointVec.push_back(a);
申请1个内存空间, 存放a. copy 1 次
2. pointVec.push_back(b);
a> 发现内存空间不够,于是扩大为原来的2倍.
b> 然后将a,b copy到新的内存空间 这里copy 2 次
c> 然后释放原来空间上的a destruction 1 次
6 楼
xflong [专家分:0] 发布于 2011-01-06 12:37:00
int main()
{
std::vector<Point> pointVec;//空的,没有构造
Point a;//构造a;
Point b;//构造b;
pointVec.push_back(a);//a作为引用实参传递给push_back,//然后push_back内部调用另一个函数insert(),而insert()函数则调用了拷贝构造函数构造临时对象,将临时对象复制给pointVec的第一个元素,push_back结束,调用析构函数析构1次(临时对象的);
pointVec.push_back(b);//这里b作为引用实参传递给push_back此时因为pointVec空间不够,故需要分配新的存储空间,push_back内部调用另一个函数insert(),而insert()函数则调用了拷贝构造函数构造临时对象,将临时对象1和原空间的元素复制到新的空间!push_back结束(对临时对象来说是超出作用域),故此时调用析构函数2次(临时对象的和原空间元素的)!
std::cout<<pointVec.size()<<std::endl;
return 0;//调用析构函数4次(对象a的,b的,以及pointVec2个元素的)
}
楼主的测试结果和我的不宜昂,我用vs2005编译运行,是上述结果!
补充说明:编译器总会为我们合成一个析构函数无论我们有没有定义自己的析构函数,也就是说,如果我们没有定义自己的析构函数那么构造了n次(包括复制构造)对象,则析构n次,如果定义了自己的析构函数则析构函数会调用2n次(因为编译总会在执行完我们自己的析构函数后,在执行合成的析构函数)上述的说明没有包含合成析构函数的次数!
void push_back(const _Ty& _Val)
{ // insert element at end
if (size() < capacity())
#if _HAS_ITERATOR_DEBUGGING
{ // room at end, construct it there
_Orphan_range(_Mylast, _Mylast);
_Mylast = _Ufill(_Mylast, 1, _Val);
}
#else /* _HAS_ITERATOR_DEBUGGING */
_Mylast = _Ufill(_Mylast, 1, _Val);
#endif /* _HAS_ITERATOR_DEBUGGING */
else
insert(end(), _Val);
}
可见2次都执行的是else后面的insert();
我来回复