如何避免大内存std::vector的对象默认初始化?
当使用std::vector分配13GB级别的大内存空间时,默认初始化容器内对象会消耗约2秒时间,而这些默认值随后会被完全覆盖,这部分开销完全没必要。
早期相关讨论里的方案多为自定义内存分配器(风险高、实现复杂且成本高)或继承std::vector,都不是理想选择。现在有没有更合理的方法?
无法使用reserve配合并行算法的问题
尝试用std::vector::reserve预分配内存,再通过std::back_inserter填充,但并行执行策略(非范围算法)要求迭代器是Cpp17ForwardIterator或更强类型,而std::back_inserter是输出(顺序)迭代器,导致代码编译失败:
#include <execution> #include <vector> int main() { std::vector source_data = { 1,2,3,4,5 }; // 实际为GB级数据 std::vector<int> v; v.reserve(source_data.size()); std::transform(std::execution::par_unseq, source_data.begin(), source_data.end(), std::back_inserter(v), [](auto in) { return in+1; // 自定义转换逻辑 }); }
编译错误:
Error C2338 static_assert failed: 'Non-ranges algorithms require that mutable iterators be Cpp17ForwardIterators or stronger.
核心诉求
希望在保留std::vector原有使用习惯的前提下,实现修改容器大小但不初始化底层元素——也就是让std::vector::size = std::vector::capacity时不触发_Uninitialized_fill_n,且不想通过自定义分配器实现。
性能对比测试
通过以下代码可以看到std::vector与new[]的性能差异:
#include <chrono> #include <vector> #include <iostream> int main() { std::chrono::high_resolution_clock::time_point start; std::chrono::high_resolution_clock::time_point end; const std::size_t size = 13'000'000'000 / sizeof(int); start = std::chrono::high_resolution_clock::now(); int *arr = new int[size]; end = std::chrono::high_resolution_clock::now(); std::cout << "Allocation with new took: " << std::chrono::duration<double>(end - start) << "\n"; start = std::chrono::high_resolution_clock::now(); std::vector<int> v(size); end = std::chrono::high_resolution_clock::now(); std::cout << "Allocation with std::vector took: " << std::chrono::duration<double>(end - start) << "\n"; // 防止过度优化 for (std::size_t i = 1; i < size; ++i) { v[i]+=v[i-1]; arr[i]+=arr[i-1]; } std::cout << v[size-1] << arr[size-1]; }
在Winx64、MSVC++2022最新版本、Release全优化环境下,测试结果为:
Allocation with new took: 0.50399s Allocation with std::vector took: 2.04084s
这1.5秒的差异就是想要避免的开销。
其他方案疑问
此前试过的其他方案(比如使用无默认初始化的底层类型)虽能避免初始化,但性能反而更差。考虑到后续无需增删元素,是否可以用std::span替代?它的接口与std::vector类似,只是不具备所有权和修改能力。
内容的提问来源于stack exchange,提问作者Damir Tenishev

