[expr.new]C++的5.3.4 2月草案给出了一个例子:
new(2,f) T[5]导致打电话operator new[](sizeof(T)*5+y,2,f).这里,x和y是非负的未指定值,表示数组分配开销; new-expression的结果将从返回的值中抵消此数量
operator new[].这种开销可以应用于所有数组新表达式,包括那些引用库函数operator new[](std::size_t, void*)和其他放置分配函数的表达式.开销的数量可能因新的一次调用而异.- 末端的例子 ]
现在来看以下示例代码:
void* buffer = malloc(sizeof(std::string) * 10);
std::string* p = ::new (buffer) std::string[10];
Run Code Online (Sandbox Code Playgroud)
根据上面的引用,第二行将new (buffer) std::string[10]在内部调用operator new[](sizeof(std::string) * 10 + y, buffer)(在构造单个std::string对象之前).问题是如果y > 0,预分配的缓冲区太小了!
那么我如何知道在使用数组放置时预先分配多少内存?
void* buffer = malloc(sizeof(std::string) * 10 + how_much_additional_space);
std::string* p = ::new (buffer) std::string[10];
Run Code Online (Sandbox Code Playgroud)
或者标准某处是否保证y == 0在这种情况下?报价再次说:
这种开销可以应用于所有数组新表达式,包括那些引用库函数
operator …
我知道这个问题过去已经被问过并得到了一些回答。
但是,我对尚未清除的细节(或者至少我找不到 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 之间有变化吗?
在C ++中,它是合法的char,unsigned char或std::byte指向别名任何T指针。这种别名指针能够访问原始内存中的对象表示。
我的问题是它是否是合法的和游离的未定义的行为,以使用一个T*从算术上派生的指针char/ unsigned char/std::byte指针混叠的原始T阵列对象序列-前提条件是所得指针仍然正确地对准和混叠序列的原始可达性内. 作为一个具体的例子:
// Array sequence is 2 in length
auto array = std::array<unsigned,2>{0xdead, 0xbeef};
// Derive the address of &array[1] using std::byte pointer
auto p = reinterpret_cast<std::byte*>(array.data());
auto p1 = reinterpret_cast<unsigned*>(p + sizeof(unsigned));
assert(p1 == &array[1]); // This expression should be legal since the pointer is safely derived
assert(*p1 == array[1]); // But is this legal, …Run Code Online (Sandbox Code Playgroud) 在了解到 std::vector 在纯 C++ 中无法实现后,我想知道是否可以在不调用 UB 的情况下编写动态数组。我们不能在没有数组的情况下进行指针运算,这意味着我们不能有一个带有部分初始化内存的动态缓冲区并将其视为数组;所以 std::vector 必须依赖于定义一些行为的实现,否则它会是 UB。
动态数组是非常普遍的数据结构,而且通常很简单。能够一致地实现这一点似乎是不可能的,这使得 C++ 看起来像是一种不太通用的系统语言,IMO。
因此,我的问题是:
注意:这里使用动态数组来表示可以“就地”增长/收缩的线性数据结构,如 std::vector 或类似地,在堆中分配的 C 缓冲区 (m)。