使用贴片新操作符时,我真的不得不担心对齐吗?

Pio*_*ycz 23 c++ g++ powerpc memory-alignment placement-new

我读过这个 什么时候应该担心对齐?但我仍然不知道我是否要担心放置新运算符返回的对齐指针 - 就像在这个例子中:

class A {
public:
   long double a;
   long long b;
   A() : a(1.3), b(1234) {}
};

char buffer[64];

int main() {
   // (buffer + 1) used intentionally to have wrong alignment
   A* a = new (buffer + 1) A(); 
   a->~A();
}
Run Code Online (Sandbox Code Playgroud)

__alignof(A) == 4,(buffer + 1)是不对齐的4.但一切正常 - 这里有完整的例子:http://ideone.com/jBrk8

如果这取决于架构,那么我正在使用:linux/powerpc/g ++ 4.xx

[更新]发布此问题后,我读了这篇文章:http://virtrev.blogspot.de/2010/09/memory-alignment-theory-and-c-examples.html.也许在我的情况下唯一的缺点是性能损失,我的意思是未对齐的访问成本超过对齐?

eca*_*mur 19

当您在缓冲区上调用placement new时:

A *a = new (buf) A;
Run Code Online (Sandbox Code Playgroud)

您正在调用内置void* operator new (std::size_t size, void* ptr) noexcept定义:

18.6.1.3安置表格[new.delete.placement]

这些函数是保留的,C++程序可能不会定义用于替换标准C++库(17.6.4)中的版本的函数.(3.7.4)的规定不适用于运营商新的和运营商删除的这些保留的安置形式.

void* operator new(std::size_t size, void* ptr) noexcept;
返回:ptr.
备注:故意不执行任何其他操作.

(3.7.4)规定包括返回的指针应该适当对齐,所以void* operator new (std::size_t size, void* ptr) noexcept如果传入一个非符号指针,则可以返回.这不会让摆脱困境,但是:

5.3.4新[expr.new]

[14]注意:当分配函数返回null以外的值时,它必须是指向已保留对象空间的存储块的指针.假设存储块被适当地对准并且具有所请求的大小.

因此,如果将未对齐的存储传递给放置新表达式,则违反了存储已对齐的假设,结果为UB.


实际上,在上面的程序中,如果你替换long long b__m128 b(之后#include <xmmintrin.h>),那么程序会像预期的那样发生段错误.


Nic*_*las 10

仅仅因为一切似乎都有效并不意味着它确实存在.

C++是一个定义工作所需内容的规范.编译器也可以使不需要的东西工作.这就是"未定义的行为"的含义:任何事情都可能发生,因此您的代码不再可移植.

C++ 不需要这个工作.因此,如果你将代码带到一个不起作用的编译器,你就不能再责怪C++了; 滥用语言是你的错.

  • C++11§3.11\ 2"对象类型具有对齐要求(3.9.1,3.9.2),它们对可以分配该类型对象的地址施加限制." 和§3.11/ 8"如果某个实现不支持特定上下文中特定扩展对齐的请求,则该程序格式错误.此外,请求运行时分配动态存储,请求的对齐无法满足应被视为分配失败." (6认同)