C ++标准第3.7.3.1节说
“分配的存储的顺序,连续性和初始值 连续调用分配函数是未指定的。“
order&的含义是什么?连续性?为什么没有说明?为什么初始值也未指定?
答案 0 :(得分:6)
<强>顺序强>
意味着分配器不限于返回稳定增加或减少的地址(或任何其他模式)。这是有道理的,因为内存通常在程序的生命周期中被回收和重复使用多次。可以从分配器中询问存储顺序是以某种方式定义的,但是在代码执行和内存效率方面,相对于相当大的开销而言,获得的收益很少(如果有的话)。
换句话说,如果B在A之后分配,而C在B之后分配,则A,B和C可以以任何顺序(ABC,BAC,CAB,CBA,......)出现在存储器中。您知道A,B和C的每个地址都是有效的,但仅此而已。
正如@Deduplicator所指出的,在并发编程中存在一个众所周知的问题叫做“ABA问题”。这是间接的原因,即新分配的对象原则上可以任何地址(注意这有点高级)。
当您使用比较交换指令以原子方式修改内存位置(例如,在无锁列表或队列中)时,会发生ABA问题。您的假设是比较交换检测到其他人同时修改了您尝试修改的指针。但是,事实是它只检测地址的位模式是否不同。现在可能会释放一个对象并将另一个对象(请求分配器存储)推送到容器,而分配器会返回完全相同的地址 - 这绝对合法。另一个线程使用了compare-exchange指令,它传递得很好。砰!
为了防范这种情况,lockfree结构通常使用带有内置引用号的指针。
<强>邻接强>
这是一个类似的约束,它基本上表示在后续分配中分配器返回的任何内容之间可能存在或不存在“漏洞”。
这意味着,如果您分配大小为8的对象,然后分配另一个对象,则分配器可能会返回地址A
和地址A+8
。但它也可能会返回地址A+10
,而不是第二次分配,由其自行决定。
这几乎是每次分配时经常发生的事情,因为除了实际对象之外,分配器通常还存储元数据,并且通常根据“桶”组织内存到特定大小(最常见的是16个字节)。
因此,如果你分配一个整数(通常是4个字节)或一个指针(通常是4或8个字节),那么在你和你分配的下一个东西之间会有一个“漏洞”。
同样,可能要求分配器以连续的方式返回对象,但与相对便宜的东西相比,这将意味着严重的性能影响。
初始值
这意味着您必须正确初始化对象并且不能假设它们具有任何特定值。不,内存将不自动进行零初始化 [1] 。
要求分配器对内存进行零初始化是可能的,但效率会低于可能的(尽管不像其他两个约束那样具有破坏性)。
<小时/> [1] 嗯,在某些情况下,它会。操作系统通常会在第一次向进程提供新页面之前将所有页面清零。这样做是为了安全,因此不会泄露任何秘密/机密数据。但是,这是一个超出C ++标准范围的实现细节。
答案 1 :(得分:1)
它实质上意味着new
运算符可以从它认为必要的系统中的任何位置分配内存,而不依赖于程序的任何分配顺序。