treating memory returned by operator new(sizeof(T) * N) as an array

The issue of pointer arithmetic on allocated memory, as in your example:

T* storage = static_cast<T*>(operator new(sizeof(T)*size));
// ...
T* p = storage + i;  // precondition: 0 <= i < size
new (p) T(element);

being technically undefined behaviour has been known for a long time. It implies that std::vector can't be implemented with well-defined behaviour purely as a library, but requires additional guarantees from the implementation beyond those found in the standard.

It was definitely not the intention of the standards committee to make std::vector unimplementable. Sutter is, of course, right that such code is intended to be well-defined. The wording of the standard needs to reflect that.

P0593 is a proposal that, if accepted into the standard, may be able to solve this problem. In the meantime, it is fine to keep writing code like the above; no major compiler will treat it as UB.

Edit: As pointed out in the comments, I should have stated that when I said storage + i will be well-defined under P0593, I was assuming that the elements storage[0], storage[1], ..., storage[i-1] have already been constructed. Although I'm not sure I understand P0593 well enough to conclude that it wouldn't also cover the case where those elements hadn't already been constructed.


The C++ standards contain an open issue that underlying representation of objects is not an "array" but a "sequence" of unsigned char objects. Still, everyone treats it as an array (which is intended), so it is safe to write the code like:

char* storage = static_cast<char*>(operator new(sizeof(T)*size));
// ...
char* p = storage + sizeof(T)*i;  // precondition: 0 <= i < size
new (p) T(element);

as long as void* operator new(size_t) returns a properly aligned value. Using sizeof-multiplied offsets to keep the alignment is safe.

In C++17, there is a macro STDCPP_DEFAULT_NEW_ALIGNMENT, which specifies the maximum safe alignment for "normal" void* operator new(size_t), and void* operator new(std::size_t size, std::align_val_t alignment) should be used if a larger alignment is required.

In earlier versions of C++, there is no such distinction, which means that void* operator new(size_t) needs to be implemented in a way that is compatible with the alignment of any object.

As to being able to do pointer arithmetic directly on T*, I am not sure it needs to be required by the standard. However, it is hard to implement the C++ memory model in such a way that it would not work.