C++ 11 std::vector push_back 方法多次调用 copy/dest?

Posted

技术标签:

【中文标题】C++ 11 std::vector push_back 方法多次调用 copy/dest?【英文标题】:C++ 11 std::vector push_back method calls copy/dest so many times? 【发布时间】:2018-12-26 03:04:30 【问题描述】:

我目前正在优化我的代码,我有一个关于 std::vector 的问题

我有一个 MyClass 类,我重写了复制/移动构造函数及其相应的运算符。

MyClass(const std::string& id, int x);
MyClass(const MyClass& other);
MyClass(MyClass&& other);
~MyClass();
MyClass& operator=(const MyClass& other);
MyClass& opratror*(MyClass&& other);

我创建了一个向量并尝试了以下

std::vector<MyClass> vec;
MyClass a("A", 1);
vec.push_back(a);    //#1
vec.emplace_back("B", 2);    //#2
vec.push_back(MyClass("C", 3));    //#3

在 #1 中调用了复制构造函数(我知道向量按值存储,因此它复制 a) 在#2中它保存了一个复制构造函数调用只调用构造函数 在 #3 中它调用构造函数并移动构造函数

但我发现,在向量不为空的 #2、#3 处,每次推回 / emplace / emplace_back 都会触发现有项目的复制/销毁。

在 #2 中,它复制“A”并销毁现有的“A” 在#3中,它对“A”和“B”做同样的事情

似乎每当数组发生变化时,向量都会使用所有项目。 这是否意味着使用类向量会使事情变得低效? 这是使用向量存储指针的最佳解决方案,以便在求助期间没有副本/析构函数调用,只有指针复制?

谢谢

【问题讨论】:

进行移动操作noexcept. 您是在运行优化的构建,还是“调试”、未优化的构建?您使用哪些编译器选项来构建代码? 试试std::vector::reserve 当向量必须重新分配其内部存储时,它会进行复制,随着它变得越来越大,这种情况发生的频率应该会降低。在得出结论之前,您放手了多大? 谢谢大家。我得到了积分!我想我需要更精确地研究 STL。 【参考方案1】:

不是度假,而是重新分配。根据约定,向量需要连续存储其值,就像普通数组一样。保证连续存储的唯一方法是分配一块内存。一旦你得到它,你就完成了。你不能让它变大。您所能做的就是分配一个更大的块并复制所有内容,然后删除旧的较小的内存块。这就是你所看到的。

向量通常会保留一些额外的额外空间,以容纳可能添加的新元素(因此这种复制不会在每次 push_back 时发生),但是当向量很小时,最初只有一点点额外空间为未来的增长而保留,这种重新分配仍然经常发生。但是随着向量大小的增长,会保留越来越多的额外空间,并且重新分配的频率会降低。

如果您事先知道要分配给push_back() 的值,您可以预先使用reserve() 预先分配额外的空间,并尽量减少重新分配。

如果您知道要再向向量添加十个值:

vec.reserve(vec.size()+10);

如果向量已经有至少十个更多的值,它可以在不重新分配的情况下接受,那么这什么都不做。否则,向量将重新分配足够的额外空间以容纳至少十个附加值。保证接下来的十个 push_backs 不会导致重新分配。

【讨论】:

【参考方案2】:

您需要采取行动 ctor noexcept(false);否则在许多情况下无法安全使用。

想象在一个适合 10 的缓冲区中有一个包含 10 个元素的向量。我们调整它的大小以适合 15,并移动其中的前 3 个。

移动第四次投掷。我们应该如何将向量恢复到正常状态?

相反,C++ 标准要求不使用投掷移动,它将 10 个元素复制到新缓冲区。成功后,它可以销毁旧缓冲区。

使用 noexcept move,它可以将 10 个元素移动到新的缓冲区。

【讨论】:

以上是关于C++ 11 std::vector push_back 方法多次调用 copy/dest?的主要内容,如果未能解决你的问题,请参考以下文章

C++,2D std::vector,我是不是需要明确保留和推回空向量?

在多线程 C++ 程序中使用 std::vector 时应用程序崩溃

C++ 指针与 std::vector:对长变量有任何影响吗?

使用并行编程 C++ 计算/访问向量

从 Swift 调用 C++ - std::vector<T> 的等价物

如何创建 C++ 用户定义的类,以便该类的 std::vector 不包含该类的某些成员