从分配器返回的内存指针算法

sky*_*ack 11 c++ pointer-arithmetic language-lawyer c++17 c++20

我知道这个问题过去已经被问过并得到了一些回答。
但是,我对尚未清除的细节(或者至少我找不到 QA)有疑问。

考虑以下代码:

T *mem = allocator_traits::allocate(allocator, 10);
allocator_traits::construct(allocator, mem+1, params...);
Run Code Online (Sandbox Code Playgroud)

mem[1]即使at的对象mem[0]还不存在,我也在构造一个对象。据我了解,指针算术在创建的非构造对象数组上定义得很好。但是,QA 不回答此特定情况:

我应该说,当我说 storage + i 将在 P0593 下明确定义时,我假设元素 storage[0], storage[1], ..., storage[i-1] 已经被构造。尽管我不确定我对 P0593 的理解是否足够好,无法得出这样的结论,即它也不会涵盖尚未构建这些元素的情况。

换句话说,作者说这可能是UB。另一方面,它会使实现无法std::vector执行以下操作:

buf_end_size = newbuf + sizeof(T) * size();
Run Code Online (Sandbox Code Playgroud)

由于我希望它是有效的代码(并且我已经在某些实现中看到了这一点),这意味着指针算术对于i没有构造对象时的任何值也有很好的定义。

所以,我的问题是:这个 UB 还是我可以allocate在任何情况下安全地对返回的指针进行指针算术,例如,如果我想在位置 0 之前在位置 1 处构造元素?另外,答案在 C++17 和 C++20 之间有变化吗?