27

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?

Community
  • 1
  • 1
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • 3
    x86 is particularly forgiving of alignment issues, powerpc not so much. – Mark Ransom Aug 02 '12 at 16:21
  • 3
    Placement new just returns the pointer as given. – R. Martinho Fernandes Aug 02 '12 at 16:21
  • Unaligned accesses are often *supported but slow*. That's the case for x86, but I don't know for PPC. – FatalError Aug 02 '12 at 16:21
  • 1
    @FatalError, with today's cache architectures I'm not sure that's true anymore. Certainly you'll see a hit if you cross a cache line boundary. – Mark Ransom Aug 02 '12 at 16:23
  • @R.MartinhoFernandes, it also calls the constructor which in this case is setting some members. If there's a problem it *should* trigger it. – Mark Ransom Aug 02 '12 at 16:25
  • IIRC, on PowerPC, unaligned integer loads are handled slowly by the processor, unaligned floating-point loads (or just doubles?) are normally handled by the OS, and unaligned vector loads give you a bus error. I also note that buffer+1 is not guaranteed to be misaligned because buffer is not guaranteed to be aligned. – tc. Sep 22 '12 at 21:59

5 Answers5

23

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.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • so what does this mean? does this mean that we have to pass to the placement new address buffer + offset, where (buffer + offset) % alignment of the class == 0 ? – bysreg May 14 '16 at 14:20
  • @bysreg sure, that would work, as long as you ensure that the space remaining is sufficient. Or you could use a facility providing a buffer that is already aligned, such as aligned_storage or posix_memalign. – ecatmur May 14 '16 at 14:44
12

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Do you mean that using not aligned pointer in placement new is UB? Can you clarify which standard says that: C++03 or C++11? – PiotrNycz Aug 02 '12 at 16:27
  • 6
    C++11 § 3.11\2 "Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated." and § 3.11\8 "If a request for a specific extended alignment in a specific context is not supported by an implementation, the program is ill-formed. Additionally, a request for runtime allocation of dynamic storage for which the requested alignment cannot be honored shall be treated as an allocation failure." – Mooing Duck Aug 02 '12 at 16:45
4

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.

Keith Randall
  • 22,985
  • 2
  • 35
  • 54
4

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.

pm100
  • 48,078
  • 23
  • 82
  • 145
3

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.

jcoder
  • 29,554
  • 19
  • 87
  • 130