【发布时间】:2018-08-26 21:10:08
【问题描述】:
我正在编写一个容器,它在内部使用alloca 在堆栈上分配数据。 Risks of using alloca aside,假设我必须将它用于我所在的领域(部分是围绕 alloca 的学习练习,部分是为了研究动态大小的堆栈分配容器的可能实现)。
根据man page for alloca(强调我的):
alloca() 函数在调用者的栈帧中分配 size 个字节的空间。 当调用 alloca() 的函数返回给它的调用者时,这个临时空间会自动释放。
使用特定于实现的功能,我设法强制内联,使调用者堆栈用于此函数级“范围”。
但是,这意味着以下代码将在堆栈上分配大量内存(编译器优化除外):
for(auto iteration : range(0, 10000)) {
// the ctor parameter is the number of
// instances of T to allocate on the stack,
// it's not normally known at compile-time
my_container<T> instance(32);
}
在不知道这个容器的实现细节的情况下,人们可能会期望当instance 超出范围时它分配的任何内存都会被释放。情况并非如此,并且可能导致在封闭函数期间出现堆栈溢出/高内存使用。
想到的一种方法是显式释放析构函数中的内存。由于没有对生成的程序集进行逆向工程,我还没有找到一种方法(另请参阅this)。
我想到的唯一其他方法是在编译时指定最大大小,使用它来分配固定大小的缓冲区,在运行时指定实际大小并在内部使用固定大小的缓冲区。这样做的问题是它可能非常浪费(假设每个容器的最大值为 256 个字节,但大多数时候只需要 32 个字节)。
因此提出了这个问题;我想找到一种方法来为这个容器的用户提供这些范围语义。不可移植是好的,只要它在其目标平台上是可靠的(例如,一些仅适用于 x86_64 的文档化编译器扩展就可以了)。
我很欣赏这可能是XY problem,所以让我清楚地重申我的目标:
- 我正在编写一个容器,该容器必须始终在堆栈上分配其内存(据我所知,这排除了 C VLA)。
- 容器的大小在编译时是未知的。
- 我希望保持内存的语义,就好像它由容器内的
std::unique_ptr持有一样。 - 虽然容器必须具有 C++ API,但使用 C 中的编译器扩展也可以。
- 代码现在只需要在 x86_64 上运行。
- 目标操作系统可以是基于 Linux 的操作系统,也可以是基于 Windows 的操作系统,无需同时在两者上运行。
【问题讨论】:
-
语句“必须始终在堆栈上分配其内存的容器”不会计算,就 C++ 而言。容器本身可以分配在堆栈(自动作用域)或堆(动态作用域)上,这完全由任何实例化容器的对象控制。但是容器本身对此绝对没有影响,无论如何。也许您在问如何声明一个只能在自动范围内声明的类。这不能在 C++ 中完成。
-
你可以写一个基于
alloca的分配器,而不是像你通常用malloc那样做的sbrk -
函数返回时释放堆栈上分配的空间。既然这不是你想要的,那你为什么确定要在栈上分配空间呢?
-
@SamVarshavchik:就 C++ 而言,容器可以分配在一堆 20 英镑的钞票上。
-
@LightnessRacesinOrbit 我喜欢那个声音
标签: c++ x86-64 alloca stack-allocation