【问题标题】:Inline allocation of memory at compile time编译时内存的内联分配
【发布时间】:2017-01-18 14:57:22
【问题描述】:

C/C++ 在编译时有多种分配内存的方法。例如,我可以添加一个全局或静态变量。存储值的内存是在编译时分配的:

int x;
// -- or --
void f() {
    static int y;
}
// -- or --
class C {
    static int z;
};
int C::z;

但是这种解决方案不能用于“内联”分配内存。是否有可能在一行中执行以下操作?

static int value_behind_x; // does not need to be "named"
int * const x = &value_behind_x;

我的意思是这样的:

int * const x = static_new int;
// -- or --
int * const x_array = static_new int[10];

我知道 C/C++ 中的一件事允许这样的事情:字符串文字。但是,它们必须是常量,并且不允许将大小指定为数字。

如果没有这样的方法,是否有原因,或者将来可能会实施?这会很好,因为它可以实现constexpr 版本的容器,例如std::vector

【问题讨论】:

  • 选择 C ​​或 C++
  • std::array不是一种“constexpr向量”吗?
  • 如果您使用 C++,听起来您可能正在寻找新的展示位置。
  • @KerrekSB 我知道std::array 但它需要将大小指定为模板参数。大小不应该是类型的一部分。甚至应该可以更改指针,使其指向动态分配的内存。
  • @JojOatXGME 编写您自己的模板函数joj_new<T>(),它将根据需要在静态或动态数据中创建对象。不过,您必须预先分配静态内存。

标签: c++ allocation constexpr compile-time


【解决方案1】:

Your statementstatic 将:

在编译时分配内存

这表明存在误解。 Static Storage Durration 已定义:

对象的存储空间在程序开始时分配,在程序结束时释放。该对象仅存在一个实例。所有在命名空间范围内声明的对象(包括全局命名空间)都有这个存储持续时间,加上那些用staticextern 声明的对象。

了解静态存储持续时间对于对抗 "static initialization fiasco" 至关重要。

通过这种理解,我们可以看到构造一个指向变量的static 指针没有性能优势,例如 static unique_ptr<const int> x(new int(13)); 而只是根据需要使用value_behind_x 的地址是最好的。

同样的事情也适用于分配具有静态存储持续时间的数组。如果您需要对数组进行容器封装,您可以使用诸如 array 之类的容器:static array<int, 10> x_array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } 但一般来说, 提供了对范围访问和容器访问的改进, 和iterator library 中的 我只是建议你坚持:

static const x_array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

编辑:

您知道,string literals 也有静态存储持续时间,这意味着您不是“在编译时分配的”。实际上C++使用的除了Static Storage Duration之外只有3 storage durations

  • 自动存储期限。该对象在封闭代码块的开头分配并在结尾处释放。除声明为staticextern 或thread_local 的对象外,所有本地对象都有此存储期限。
  • 线程存储持续时间。对象在线程开始时分配,在线程结束时释放。每个线程都有自己的对象实例。只有声明为 thread_local 的对象具有此存储持续时间。 thread_local 可与staticextern 一起出现以调整联动。
  • 动态存储持续时间。使用动态内存分配函数根据请求分配和释放对象。

所以不,运行前没有分配或初始化。我也不期望永远存在,因为这需要基本的 C++ 意识形态改变在某种程度上改变计算机架构。

【讨论】:

  • 我知道static std::vector x = {a, b, c}会在调用main()之前在运行时分配内存。但是,使用static_new 之类的东西,可以实现std::vector 的版本,它可以处理这种情况,而无需在运行时分配和初始化内存。它只会在销毁时产生很小的开销,因为它必须检查内存是否是静态的。也许实现还需要constexpr 的alternativ 关键字,它只允许在编译时执行(不能同时执行)。
  • @JojOatXGME 啊,所以你问这个:stackoverflow.com/questions/29394937/… 或者你问的是应用程序:stackoverflow.com/q/29848547/2642059
  • 是的,第二个 (int* to Constant Array) 匹配我的问题的一部分。我将扩展非常数数组和给定大小的数组的问题,而不指定每个项目(又名。static_new int[4])。由于我猜到还没有这样的功能,所以我进一步询问将来是否会在 C++ 中添加一些功能。
  • @JojOatXGME 例如,我认为您对字符串文字仍有一些误解。我试图澄清一下我的答案。你提出constexpr 可能应该得到解决。这些变量在编译时是完全可初始化的,编译器可以使用这些变量来做出优化和可能修剪代码分支的决策。但即使是在运行时使用的constexpr 变量也将具有静态或自动存储持续时间。
  • 在编译时有某种类型的存储分配和初始化。如果你写int x = 4;,你的编译器会在数据段中分配4个字节并写入4。但是,由于constexpr-functions 可以在运行时使用动态参数执行,因此这种分配在这里不起作用。这意味着您是对的,可以在这两种情况下处理分配的实现是不可能的。尽管如此,通过为constexpr 提供一个仅允许在编译时执行的替代关键字,您将绕过该问题。但就我写这个问题而言,我还没有想到。 ://
【解决方案2】:

首先,具有静态持续时间的变量的内存在编译时并没有真正分配。它是在链接时甚至在启动时分配的。虽然差异很细微,但在某些情况下很重要。

其次,您正在寻找的似乎是一种分配具有自动或静态持续时间的数据块的方法。传统上,它是使用 C 样式数组 std::array 完成的,并且在可用时使用 VLA 扩展作为 VLA 数组。

【讨论】:

  • 据我所知,VLA 不是在编译时/链接时分配的(没有静态持续时间)。毕竟,它们具有本地范围并且不能位于静态内存中,因为在某些情况下您可能需要多个实例。据我所知,它们被放置在堆栈上。
【解决方案3】:

请求的功能部分计划用于 C++20。目前只允许临时分配。

这意味着new 将在编译时有效。但是,在编译时分配的内存目前不允许泄漏到运行时。这个限制背后的原因可以在P0784 中找到。未来版本可能会添加对非瞬态分配的支持。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-31
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    相关资源
    最近更新 更多