如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?

How to allocate memory for std::vector and then call constructor for some elements later?

本文关键字:元素 调用 构造函数 std vector 分配 内存 然后      更新时间:2023-10-16

我正在"现代化"一个(相当古老的(C++项目,并偶然发现了这部分:

旧代码为动态数组分配内存,然后根据需要稍后为元素调用构造函数。我想为所有元素调用构造函数是昂贵的,所以作者选择这样做(性能对这个项目至关重要(。旧代码如下所示(简化(:

struct my_struct {
my_struct(int x, int y, int z) { /* expensive ctor */ }
};
struct other_class {
my_struct* arr;
other_class(int n) {        
arr = (my_struct*) malloc(n * sizeof(arr[0]);
}
void foo(int idx, int a, int b, int c) {
new (&arr[idx]) my_struct(a, b, c);
}
};

我将arr更改为std::vector<my_struct>,并使用std::reserve来"保留"内存。代码工作正常,通过所有当前测试,但我知道这不行,因为std::reserve不会增加该向量的大小,因此调用arr.size()仍将返回 0。这是我的代码:

struct other_class {
std::vector<my_struct> arr;
other_class(int n) {        
arr.reserve(n);
}
void foo(int idx, int a, int b, int c) {
new (&arr[idx]) my_struct(a, b, c);
}
};

如何使这段代码快速安全(假设我无法向my_struct添加默认 ctor (?谢谢。


编辑:这是示例代码。它按预期编译和运行,没有任何警告:http://cpp.sh/8ytwf

但我知道这不行,因为 std::reserve 不会增加该向量的大小

std::reserve确实增加了向量容量,当您只想分配内存并且稍后才推送元素时,这正是您想要的。

向量管理的基础数组的大小不等于向量size()size()返回容器中的元素数,只要没有任何size() == 0

当你稍后推送元素时,你不需要使用放置new,但你应该使用push_backemplace_back。更具体地说,这是错误的:

new (&arr[idx]) my_struct(a, b, c);

因为您正在越界访问向量(请记住:大小是元素的数量,容量可以更大,但您不能访问大于向量大小的索引(。相反:

arr.emplace_back(a,b,c);

虽然我更喜欢emplace_back解决方案,但在这种情况下您可以使用std::optional。这将允许您使用idx来确定使用有效对象填充哪个元素。

struct other_class 
{
std::vector<std::optional<my_struct>> arr;
other_class( int n ) : arr( n, std::nullopt )
{ }
void foo( int idx, int a, int b, int c ) 
{
arr.at( idx ).emplace( a, b, c );
}
};