Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to work with pointers into raw memory provided by custom allocators (without UB)?

I am trying to write an allocator-aware container. Suppose I want to allocate a chunk of memory for three objects:

T* chunk = std::allocator_traits<Allocator>::allocate(allocator, 3);

(I know that allocators can have custom pointer types and therefore I should use std::allocator_traits<Allocator>::pointer; I am using raw pointers here for simplicity.)

Now I want to create an actual object at index 2. How do I do that? In particular, how do I calculate the pointer to the not-yet-existing element? The most obvious option would be the following:

std::allocator_traits<Allocator>::construct(allocator, chunk + 2, ...);

Unfortunately, chunk + 2 does not appear to be correct: according to the standard, pointer arithmetic can only be performed on pointers to array elements, and otherwise it causes undefined behavior. For the same reason, I cannot convert the pointer to std::byte* and use pointer arithmetic on that. (While std::allocator is defined to create an array in newly allocated memory, until C++20, the same requirement does not exist for custom allocators. Also, while C++20 adds some language for “implicit creation of objects”, this does not apply for earlier C++ versions.)

So how do I calculate the pointer to give as the second argument to construct without causing undefined behavior (before C++20)?

like image 619
voidf.0xb3 Avatar asked Oct 15 '22 01:10

voidf.0xb3


1 Answers

In the latest standard draft (C++20):

[tab:cpp17.allocator]

a.allocate(n) - Memory is allocated for an array of n T and such an object is created but array elements are not constructed.

allocator_traits::allocate(n) simply calls a.allocate(n).

So, given that the array is created, the pointer arithmetic is well defined.


In C++17 before the acceptance of proposal P0593R6, the wording was:

Memory is allocated for n objects of type T is created but objects are not constructed.

Prior to this change there was no well-defined way to do what you are asking unless:

  • We assume that the custom allocator provides the guarantee that such array is created. Problem with this is that there is no standard way to create an array without creating the objects (without the default allocator) and thus no standard way to implement such custom allocator.
  • We ignore the restrictions of pointer arithmetic. Theoretical problem with this is the undefined behaviour. In practice, this has not been a problem with actual language implementations.
like image 137
eerorika Avatar answered Oct 18 '22 15:10

eerorika