我有一个概念,即C ++运行时不执行任何堆压缩,这意味着在堆上创建的对象的地址永远不会改变。我想确认这是否属实,以及是否适用于每个平台(Win32,Mac,......)?
答案 0 :(得分:18)
C ++标准对堆没有任何说明,也没有说压缩。但是,它确实要求如果你获取一个对象的地址,那么该地址在整个对象的生命周期内保持不变。
C ++实现可以进行某种堆压缩并在后台移动对象。但是当你使用address-of运算符时,它返回给你的“地址”实际上并不是内存地址,而是一些其他类型的映射。
换句话说,是的,可以安全地假设C ++中的地址与您获取生命地址的对象保持一致。
幕后发生的事情未知。 物理内存地址可能会发生变化(虽然常见的C ++编译器不会这样做,但它可能与针对各种形式的字节码的编译器相关,例如Flash),但是你的程序的地址看起来会表现得很好。
答案 1 :(得分:4)
标准没有指定它,但是标准没有指定堆。这完全取决于您的实施。但是,没有什么能阻止实现压缩未使用的内存,同时为正在使用的对象保留相同的地址。
答案 2 :(得分:4)
你说得对,它不会改变。页面可以在物理内存中移动,但是Translation Lookaside Buffer(这就是控制虚拟内存)会隐藏所有内容。
答案 3 :(得分:3)
我不知道任何将移动已分配对象的C ++实现。我认为标准可能在技术上允许(虽然我不是100%肯定),但请记住,标准必须允许指针被强制转换为足够大的整数类型并再次返回并且仍然是有效的指针。因此,可以移动动态分配的对象的实现必须能够处理不可能发生的一系列事件:
实现需要确保指向最后一步的指针指向移动对象的新位置。
我认为对指针使用双重间接可能允许实现来处理这个问题,但是我不知道有任何类似的实现。
答案 4 :(得分:2)
在正常情况下,当您使用系统编译器的默认运行时时,您可以安全地假设运行时不会使指针无效。
如果您不使用默认内存管理器,而是使用第三方内存管理器,则完全取决于您使用的运行时和内存管理器。虽然C ++对象通常不会被内存管理器在内存中移动,但是你可以编写一个压缩可用空间的内存管理器,你可以设想一个可以移动已分配对象的内存管理器,以便最大化可用空间。