Question

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) is not aligned to 4. But everything works fine - full example here: http://ideone.com/jBrk8

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

[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?

Was it helpful?

Solution

When you call placement new on a buffer:

A *a = new (buf) A;

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

18.6.1.3 Placement forms [new.delete.placement]

These functions are reserved, a C++ program may not define 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.

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:

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.

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.


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.

OTHER TIPS

Just because everything appears to work doesn't mean it actually does.

C++ is a specification that defines what is required to work. The compiler can also make not required things work. That's what "undefined behavior" means: anything can happen, so your code isn't portable anymore.

C++ does not require this to work. So if you take your code to a compiler where this doesn't work, you can't blame C++ anymore; it's your fault for misusing the language.

Yes, it all depends on the architecture, and probably the compiler optimization flags as well. It will all work fine until you do A b = a; or some other random access which gets compiled to some movdqa ops and your program crashes.

some processors will definitely blow up with this (sparc for example), others will not care at all, others will be slow. C++ is assuming that you know what you are doing (or not), same as reinterpret_cast etc.

a quick google tells me that gcc on powerpc has an option to tell the compiler if unaligned accesses are handeled by the system or not.

I would assume that in either case unaligned accesses on that platform will be very slow, and should be avoided as much as possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top