C++语言规范层级所定义的运行时内存模型到底是怎么样的?

最近在学C++有一个问题我不是很理解, 也是第一次在本社区提问(被同学拉进来的), 有不规范的地方还望指出(
这里所说的 “内存模型” 是指 栈、栈帧和堆(人们常说new时将在这里创建对象)
就是下面所说的这个样子

但我在B站上学习闲逛的时候也有人提出了反对
比如【辟谣】C++根本没有堆和栈!_哔哩哔哩_bilibili


包括我关注的"mq白cpp"也持有相同的观点

我在C++文档里没有找到有关的信息(也可能是没找到())
https://zh.cppreference.com/w/cpp

所以我很好奇有无官方的有关规定

2 个赞

说说自己的看法, 仅供参考
我觉得 具体的内存分配方式和底层实现细节,如堆和栈的具体布局,由编译器和运行时系统决定,而不是由 C++ 标准所规定.
C++11 ISO标准 第1.7章 有写 C++ 内存模型, 但是没有规定 内存分配方式和底层实现细节.

1 个赞

说说自己的看法, 仅供参考

我觉得 其实你不用烦恼 C++运行时的内存模型: 堆, 栈, 静态存储区, 常量存储区等
上面这些就是C++运行时内存布局常见实现(最优?)

如果你对底层感兴趣 那就去了解 堆, 栈, 静态存储区, 常量存储区等概念
例如 函数参数是怎么传参的
为什么 std::printf 函数的参数是可变的
__stdcall 和 __cdecl 等调用约定 他们有什么不同
为什么我们可以重载 new 和 delete?
传参时 栈空间是如何变化的 等等

我们再做个假设 你自己开发一个C++编译器 能将代码里面的所有变量都通过内存池来分配 变量不在使用时 还能自动回收内存.
请问这种方式的C++ 运行时的内存模型是什么样的?

2 个赞

有一定道理。Technically, c++的内存模型是抽象的,只是编译器负责具体实现,例如ebp,esp是汇编的,超出了范畴。但是栈和堆即使不存在也可以理解成这样,我们就是这样学的
open-std.org

1 个赞

我对语言抽象层的理解是:
语言设计者/团队希望你把最多到这里的事情做好就可以了(以及不要再向下了)

简单的说, 就是

  1. 更少地写出未定义行为
  2. 更多地写出平台兼容编程

我之前的写 python 的
python 就很大方的承认并给出了解释器里call stack的各种接口(比如可以很轻松的得到调用你的函数的函数名甚至于它的各个参数) (对应C++人们常说的"栈")

并且 python 中只有 function scope 会建立新的作用域,也就是说在 python 的"自由储存空间" (对应C++中人们常说的"堆")

清晰的给出了 python 的运行时内存模型同时也是在告诉你,后面的事情你就别做了,比如自己通过 C API 主动击穿抽象去做一些比如解除GIL等等比较"疯狂"的行为

回到C++来说, 我们在debug模式下通常能看到变量的地址是紧挨着排列的, 所以我看到有些所谓教程在给出了"使用变量X的指针仅通过位移来访问变量Y"的所谓"黑科技"

然而事实上只有在 结构体 和 数组 (反正我目前是知道这两个())当中才可以使用变量的偏移来访问数据, 因为C++是这样规定的,它要求实现它的编译器必须做到结构体的内存对齐等等, 任何具体的实现都必须做到这一点, 所以我认为语言的抽象大大减轻了使用者的心智负担

故我认为了解语言自己的抽象内存布局是很有必要的(

所以是说确实存在逻辑栈和堆但是不应该依赖它们的相对位置(内存地址上的数值关系)来做一些操作是吧(