如何使用指向自定义分配器(无 UB)提供的原始内存的指针?

voi*_*xb3 5 c++ undefined-behavior allocator language-lawyer c++17

我正在尝试编写一个分配器感知容器。假设我想为三个对象分配一块内存:

T* chunk = std::allocator_traits<Allocator>::allocate(allocator, 3);
Run Code Online (Sandbox Code Playgroud)

(我知道分配器可以有自定义指针类型,因此我应该使用std::allocator_traits<Allocator>::pointer;为了简单起见,我在这里使用原始指针。)

现在我想在索引 2 处创建一个实际对象。我该怎么做?特别是,如何计算指向尚不存在的元素的指针?最明显的选项如下:

std::allocator_traits<Allocator>::construct(allocator, chunk + 2, ...);
Run Code Online (Sandbox Code Playgroud)

不幸的是,chunk + 2似乎并不正确:根据标准,指针运算只能对指向数组元素的指针执行,否则会导致未定义的行为。出于同样的原因,我无法将指针转换为指针std::byte*并对其使用指针算法。(虽然std::allocator定义为在新分配的内存中创建数组,但在 C++20 之前,自定义分配器不存在相同的要求。此外,虽然 C++20 增加了一些“隐式创建对象”的语言,但这并没有申请较早的 C++ 版本。)

那么如何计算要作为第二个参数给出的指针construct而不导致未定义的行为(在 C++20 之前)?

eer*_*ika 3

在最新的标准草案(C++20)中:

[选项卡:cpp17.分配器]

a.allocate(n) - 为n T 的数组分配内存,并创建这样的对象,但不构造数组元素。

allocator_traits::allocate(n)只需调用a.allocate(n).

因此,鉴于创建了数组,指针算术已明确定义。


在接受提案 P0593R6 之前的 C++17 中,写法是:

创建了 n 个类型为 T 的对象,但未构造对象,因此分配了内存。

在此更改之前,没有明确的方法来执行您所要求的操作,除非:

  • 我们假设自定义分配器提供了创建此类数组的保证。问题在于,没有标准方法可以在不创建对象的情况下创建数组(没有默认分配器),因此没有标准方法来实现此类自定义分配器。
  • 我们忽略指针运算的限制。理论上的问题是未定义的行为。实际上,这对于实际的语言实现来说并不是问题。