当“std::vector”调整内存大小时,避免使用任何自动变量

Avoiding any automatic variables when `std::vector` resizes its memory

本文关键字:任何自 变量 vector std 调整 内存 小时      更新时间:2023-10-16

我有一个std::vector<SomeType>,而SomeType是从各种模板参数实例化的struct

最终,在我的具体案例中,它变成了一个大型结构(大约1MB)。在堆栈上分配这样的结构(即使用这种类型的自动变量)会立即导致堆栈溢出。但是由于std::vector在堆上分配内存,因此应该没有问题。

令人惊讶的是,存在问题。具体来说,问题出在初始化上。我做以下事情:

std::vector<SomeType> myVec;
// ...
myVec.resize(N);
for (size_t i = 0; i < N; i++)
{
    SomeType& x = myVec[i];
    // initialize it
}

我在myVec.resize()中得到一个堆栈溢出异常。使用调试器进入resize()会发现,如果resize()导致vector增长,那么除了分配内存外,它还会通过"默认值"初始化新元素。

"默认值"是通过创建给定类型的自动变量,使用默认(即空)构造函数,并将新元素分配给它来获得的。

我想知道是否有办法克服这个问题。我的意思是,告诉std::vector不要初始化新元素。但我希望在不生成不需要的代码的情况下实现这一点。

我可以考虑使用vector(smart/shared/scoped/unique)指针来类型。或者使用push_back,而每个新元素都在堆上分配。但所有这些不可避免的事情都涉及到额外的代码。这是不合理的。

有没有办法达到我的需要?鉴于:

  • 仍在使用std::vector<SomeType>
  • 无冗余堆分配

提前感谢

在C++03中,这是不可能的:

  • 矢量不能包含未初始化的元素
  • 矢量只有知道如何通过复制初始化元素

因此,您需要从中复制一个元素。它不适合堆栈(排除了默认参数),而且你不想明确地把它放在其他地方,所以你运气不好。

在C++11中,有新的初始化容器中元素的方法,例如size_t构造函数不再使用额外的默认参数。相反,它值初始化每个元素,这可能是您想要的。

所以在C++11中,答案是std::vector<SomeType> myVec(N);。也许您可以检查编译器是否有可用于编译代码的C++11模式。当然,迁移到C++11并不是一件小事。

使用reserve,然后使用push_back。

最好的解决方案是更改SomeType,使其更小。但在不使用堆栈或堆的情况下调整向量大小是可能的。只需使用一个静态局部变量:

static SomeType intialValue;
myVec.resize(N, initialValue);

请注意,这样的功能是不可重新进入的。

相关文章: