我正在使用C ++进行练习但是我得到了意想不到的输出,我希望有人可以解释。练习要求我创建一个名为rock的类,它有一个默认的构造函数,一个复制构造函数和一个析构函数,所有这些都会向cout宣布自己。
在main方法中,我尝试按值添加此类的成员:
vector<Rock> byValue;
Rock r1, r2, r3;
byValue.push_back(r1);
byValue.push_back(r2);
byValue.push_back(r3);
cout << "byValue populated\n\n";
我预期的输出(并在练习题中显示)是:
Rock()
Rock()
Rock()
Rock(const Rock&)
Rock(const Rock&)
Rock(const Rock&)
byValue populated
~Rock()
~Rock()
~Rock()
~Rock()
~Rock()
~Rock()
然而我得到的输出是:
Rock()
Rock()
Rock()
Rock(const Rock&)
Rock(const Rock&)
Rock(const Rock&)
~Rock()
Rock(const Rock&)
Rock(const Rock&)
Rock(const Rock&)
~Rock()
~Rock()
byValue populated
~Rock()
~Rock()
~Rock()
~Rock()
~Rock()
~Rock()
任何人都可以解释为什么似乎有额外的复制构造函数和析构函数调用?
答案 0 :(得分:8)
当向量调整大小时,必须将元素移动到新位置。
这很正常。
如果你打电话
byValue.reserve(10);
在调用push_back
之前,额外的副本应该会消失。
答案 1 :(得分:4)
向量连续存储其元素。为了避免每次插入元素时总是重新分配内存,它会分配一堆内存。这就是为什么vector有两个关于它的“大小”的方法:size()
表示存储的元素数量,capacity()
表示分配的内存量。
通常(但这取决于STL实现),它通过将其先前容量加倍而增长。当它分配更多内存,并且因为数据必须连续存储(与list
相比),它必须移动其内部数据;并且STL复制数据,这就是你对构造函数/析构函数进行如此多调用的原因。
如果您知道向量中将存储多少元素,则可以使用reserve
来指示最初应分配多少内存。
答案 2 :(得分:1)
std::vector
存储元素的内存有限。您可以使用capacity
查询多少。您还可以使用reserve
方法告诉矢量获取额外的内存。
当你将一个元素推到向量上并且它的容量为零(它已经用完所有额外的内存)时,它会分配一个新的更大的数组并复制原始元素。这就是所有额外副本的来源。
查看输出,看起来矢量必须增长两倍。如果您在推送任何内容之前更改为调用保留的代码,则向量将永远不需要增长,并且不会有额外的副本。
这是一个详细的代码段,展示了所有这些如何结合在一起:ideone.com