为何测试代码中std::vector移动赋值相比复制无明显性能优势
问题原因分析
- 你的测试用例的性能瓶颈完全不在赋值操作上,整体耗时被其他更高开销的操作覆盖了:
10万次循环里,每次都要执行vector<int> nums2(1000)的内存分配、1000次rand()调用赋值、还有cout输出+退格操作,这几部分的开销占了总耗时的99%以上。移动赋值和复制赋值的耗时差异在这些大开销操作面前完全可以忽略,所以你测出来的总耗时基本一致。 - 你对
std::vector移动赋值的理解没有错误:移动赋值确实是O(1)复杂度,仅需要交换容器内部的三个指针(数据首地址、已用空间尾地址、总容量尾地址),不需要拷贝任何元素;而复制赋值是O(N)复杂度,需要拷贝所有元素。 - 额外的干扰因素:
nums在第一次赋值后容量就已经达到1000,后续的复制赋值不需要重新申请内存,仅需要拷贝1000个int(共4KB),在O3优化下,连续小内存的拷贝速度极快,就算没有其他开销干扰,和O(1)移动操作的耗时差距也很容易被测量误差掩盖。
正确的测试方案
你需要把要测量的赋值操作和其他开销隔离开,示例代码如下:
#include <iostream> #include <vector> #include <chrono> using namespace std; const int kLoopCount = 100000; const int kVecSize = 1000; int main() { // 提前准备好所有测试用的源vector,排除构造、赋值rand的开销 vector<vector<int>> source(kLoopCount); for (int i = 0; i < kLoopCount; ++i) { source[i].resize(kVecSize); for (int j = 0; j < kVecSize; ++j) { source[i][j] = rand(); } } vector<int> nums; auto start = chrono::steady_clock::now(); // 仅测量赋值操作的耗时 for (int i = 0; i < kLoopCount; ++i) { // 复制赋值版本 // nums = source[i]; // 移动赋值版本 nums = move(source[i]); } auto end = chrono::steady_clock::now(); cout << "Time: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms\n"; // 防止编译器优化掉nums相关操作 cout << nums[0] << endl; return 0; }
用相同的编译参数测试,移动赋值版本的耗时会比复制赋值版本低1~2个数量级,就能明显看出性能差异。
内容的提问来源于stack exchange,提问作者Christopher Miller
相关产品推荐
相关产品推荐

