为什么向量初始化会构造和复制?

5

我正在学习C++,并且一直在研究STL容器。我有很多问题,但是我想先谈论这个。考虑下面的类和它的向量。

class A {
   int i;
   // A(const A&);
public:

   A(int i) : i(i) {cout << "consting " << i << endl;}
   A(const A& ot) : i(ot.i) {cout << "copying " << i << endl;}

};

int main () {
   vector<A> v1 = {A(1),A(2),A(3),A(4)};
   vector<A> v2(1,A(5));
   vector<A> v3;
   v3.push_back(A(6));
}

给我输出结果

consting 1
consting 2
consting 3
consting 4
copying 1
copying 2
copying 3
copying 4
consting 5
copying 5
consting 6
copying 6

显然,它正在构造并复制每个A

有没有什么方法可以防止这种情况发生。我的意思是如何避免额外的复制,并将A直接构造到向量中。是否有可能?如果不行,能有人解释一下为什么吗?谢谢。

编辑: 为了完整起见,push_back也是一样的


3
问题在于 std::initializer_list "拥有" 它的内容,因此每个使用它的构造函数都必须复制这些元素。这虽然不合理,但这就是 std::initializer_list 的工作方式。很遗憾。 - ipc
@ipc 其他构造情况呢?其他的也可能吗? - user2267860
@Aurora:实际上,这比你想象的要容易得多。不要添加A(6),只需添加6即可。 - Mooing Duck
2个回答

4

不幸的是,使用 std::vector 进行列表初始化需要进行复制操作。如果您知道您的容器是固定大小的,则可以考虑使用 std::array

std::array<A, 4> a1 = {{A(1),A(2),A(3),A(4)}};

stdout:
consting 1
consting 2
consting 3
consting 4

3
当使用初始化列表构造函数时,无法避免生成副本。另一种方法是在开始时保留适当的容量,然后每次使用emplace_back添加对象:
vector<A> v1;
v1.reserve(4);
v1.emplace_back(1);
v1.emplace_back(2);
v1.emplace_back(3);
v1.emplace_back(4);

正如您所看到的, 这将只产生以下输出:

consting 1
consting 2
consting 3
consting 4

3
没问题,但你正在使用的初始化列表构造函数也是如此。 - Joseph Mansfield
@Aurora:正确。同样适用于您在代码中使用的初始化列表。 - user405725
其实我尝试过那个,希望它会给出不同的结果。对于普通构造函数和 push_back,我想除了使用 C++11 之外没有其他办法了吧? - user2267860
1
@Aurora 不,除了 std::vector<A> v1(5);(需要默认构造函数),在 C++11 之前没有办法进行 emplace 构造。 - Joseph Mansfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接