使用placement new操作符时我真的需要担心对齐吗?

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

I read this When should I worry about alignment? but I am still do not know if I have to worry about not aligned pointer returned by placement new operator - like in this example:

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();
}

__alignof(A) == 4(buffer + 1) 未与 4 对齐.但一切正常 - 完整示例:http://ideone.com/jBrk8

__alignof(A) == 4, (buffer + 1) is not aligned to 4. But everything works fine - full example here: http://ideone.com/jBrk8

如果这取决于架构,那么我使用的是:linux/powerpc/g++ 4.x.x.

If this depends on architecture then I am using: linux/powerpc/g++ 4.x.x.

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

[UPDATE] Just after posting this question I read this article: http://virtrev.blogspot.de/2010/09/memory-alignment-theory-and-c-examples.html. Maybe the only drawbacks in my case would be performance penalty, I mean unaligned access cost more than aligned?

推荐答案

当你调用placement new on a buffer时:

When you call placement new on a buffer:

A *a = new (buf) A;

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

you are invoking the built-in void* operator new (std::size_t size, void* ptr) noexcept as defined in:

c++11

这些函数是保留的,C++ 程序不能定义替换版本的函数标准 C++ 库 (17.6.4).(3.7.4) 的规定不适用于这些保留的放置形式运算符 new 和运算符 delete.

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

These functions are reserved, a C++ program may not de?ne functions that displace the versions in the Standard C++ library (17.6.4). The provisions of (3.7.4) do not apply to these reserved placement forms of operator new and operator delete.

void* operator new(std::size_t size, void* ptr) noexcept;
Returns: ptr.
Remarks: Intentionally performs no other action.

(3.7.4) 的规定 包括返回的指针应该适当对齐,所以 void* operator new (std::size_t size, void* ptr) 没问题noexcept 如果传入一个指针,则返回一个未对齐的指针.不过,这不会让 你 摆脱困境:

The provisions of (3.7.4) include that the returned pointer should be suitably aligned, so it's fine for void* operator new (std::size_t size, void* ptr) noexcept to return a nonaligned pointer if one is passed in. This doesn't let you off the hook, though:

[14] 注意:分配函数返回null以外的值时,必须是指向存储块的指针为对象预留的空间.假定存储块已适当对齐和要求的大小.

5.3.4 New [expr.new]

[14] Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size.

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

So if you pass unaligned storage to a placement-new expression you're violating the assumption that the storage is aligned, and the result is UB.

确实,在上面的程序中,如果将 long long b 替换为 __m128 b(在 #include <xmmintrin.h> 之后) 那么程序就会出现段错误,正如预期的那样.

Indeed, in your program above, if you replace long long b with __m128 b (after #include <xmmintrin.h>) then the program will segfault, as expected.

相关文章