[英]vector push_back calling copy_constructor more than once?
我对向量push_back的行为感到有些困惑,在以下代码段中,我希望复制构造函数仅被调用两次,但输出表明并非如此。 是导致这种行为的向量内部重组吗?
输出:
Inside default Inside copy with my_int = 0 Inside copy with my_int = 0 Inside copy with my_int = 1
class Myint
{
private:
int my_int;
public:
Myint() : my_int(0)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
void set(const int &x)
{
my_int = x;
}
}
vector<Myint> myints;
Myint x;
myints.push_back(x);
x.set(1);
myints.push_back(x);
怎么了:
x
是通过push_back
插入的。 出现一个副本:用参数初始化新创建的元素。 my_int
被视为零,因为x
的默认构造函数my_int
其初始化。
第二个元素是push_back
; 由于已达到内部容量 ,因此向量需要重新分配内存。
由于没有为Myint
1隐式定义move构造函数,因此选择了复制构造函数。 第一个元素被复制到新分配的内存中(它的my_int
仍然为零...因此复制构造函数再次将my_int
显示为0
),然后复制x
来初始化第二个元素(与步骤1中的第一个元素一样)。 这次x
将my_int
设置为1,这就是复制构造函数的输出告诉我们的。
因此,通话总数为三。 这可能因一个实现而异,因为初始容量可能不同。 但是,最少要打两个电话。
您可以通过预先保留更多内存来减少副本数量-即更高的向量容量,因此无需重新分配:
myints.reserve(2); // Now two elements can be inserted without reallocation.
此外,在插入时,您可以删除副本:
myints.emplace_back(0);
这“放置”了一个新元素emplace_back
是一个可变参数模板,因此可以接受任意数量的参数,然后将其转发给元素构造函数,而无需复制或移动。
1因为有一个用户声明的副本构造函数。
当通过第二个push_back
增加向量的大小时,必须将向量的现有内容复制到新缓冲区中。 要进行验证,请在第一个push_back
之后输出myints.capacity()
,它应为1
。
这取决于为std::vector
类型的对象保留了多少内存。 似乎在第一次执行push_back
,仅为一个元素分配了内存。 当第二次调用push_back
时,将重新分配内存以为第二个元素保留内存。 在这种情况下,矢量中已经存在的元素将被复制到新位置。 然后添加第二个元素。
您可以自己保留足够的内存,以逃避复制构造函数的第二次调用:
vector<Myint> myints;
myints.reserve( 2 );
你明白了...它正在调整大小。 但我只是指出,如果您要依靠构造函数进行bean计数,您可能会对“放置”感兴趣:
#include <iostream>
#include <vector>
using namespace std;
class Myint
{
private:
int my_int;
public:
explicit Myint(int value = 0) : my_int(value)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
Myint(const Myint&& x) noexcept : my_int(x.my_int) {
cout << "Inside move with my_int = " << x.my_int << endl;
}
};
int main() {
vector<Myint> myints;
myints.reserve(2);
myints.emplace_back(0);
myints.emplace_back(1);
// your code goes here
return 0;
}
那应该给你:
Inside default
Inside default
而且,由于move构造函数上的noexcept ...如果删除reserve
您将获得移动,而不是副本:
Inside default
Inside default
Inside move with my_int = 0
副本上移动的这种数据类型没有真正的优势。 但是从语义上讲,如果您的数据类型更“重”,并具有“移动”其成员的方式,这更像是将某个指针的所有权转移到大型数据结构,则可能会有很大的不同。
您假设复制构造函数的其他调用来自向量的内部重组是正确的。
请参阅此答案以获取更多详细信息: https : //stackoverflow.com/a/10368636/3708904
或出于需要构造副本的原因而给出以下答案: https : //stackoverflow.com/a/11166959/3708904
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.