struct T{
T(){}
~T(){}
};
int main(){
auto ptr = (T*)malloc(sizeof(T)*10); // #1
ptr++;
}
由于T
不是隐式生存期类,因此操作malloc
永远不能隐式创建类类型为T
的对象。在本例中,我们打算使ptr
指向具有10个类型为T
的元素的数组对象的初始元素。基于这个假设,ptr++
将具有有效的行为。根据[interro.object]p11
此外,在指定的存储区域内隐式创建对象后,一些操作被描述为生成指向适当创建的对象的指针。这些操作选择一个隐式创建的对象,其地址是存储区域开始的地址,并且生成一个指向该对象的指针值(如果该值将导致程序具有定义的行为(。
由于任何类型的数组都是隐式生存期类型,malloc(sizeof(T)*10)
可以隐式创建一个包含10个元素的数组对象,并开始该数组对象的生存期。由于初始元素和包含数组不是指针可交换的,ptr
永远不能指向该数组的初始元素。相反,该操作只能生成数组对象的指针值。有了这个假设,我们应该把#1
分为几个步骤,使程序形成良好的形式?
// produce the pointer value points to array object of 10 T
auto arrPtr = (T(*)[10])malloc(sizeof(T)*10);
// decay the array
auto ptr =*arrPtr; // use array-to-pointer conversion
ptr++;
我们应该首先获取数组指针,并使用该指针值来获取初始元素指针值?这些过程对于使程序形成良好的形式有必要吗?
我认为第一个例子非常有效,但毫无意义。malloc返回的数组尚未初始化任何对象。虽然我认为你可以形成一个指向每个对象的指针并在数组上迭代,但你在任何时候都不能取消引用指针。
在我看来,这里唯一缺少的是使用placement new或construct_at,如下所示:
struct T{
T(){}
~T(){}
};
int main(){
constexpr int SIZE = 10;
auto ptr = (T*)malloc(sizeof(T)*SIZE); // #1
for (auto p = ptr; p < &ptr[SIZE]; ++p) {
std::construct_at(p);
}
ptr++;
}
数组中的对象只能使用指针算术或数组索引ptr[i]
来构造,这相当于*(ptr+i(,因此与p++
基本相同。如果您的初始示例是UB,那么上面的construct_at调用也将是UB。唯一的解决方法是将malloc的返回视为字节数组,并在每个大小为(T(字节的情况下调用construct_at。在构建之后,我希望阵列可以被铸造成正确的类型。但这是愚蠢的,我希望没有人能找到必要的理由。
总的来说,如果你的例子是非法的,那么你将如何实现new((本身?