jac*_*k X 19 c++ language-lawyer c++20
struct T{
T(){}
~T(){}
};
int main(){
auto ptr = (T*)malloc(sizeof(T)*10); // #1
ptr++;
}
Run Code Online (Sandbox Code Playgroud)
由于T不是隐式生命周期类,因此该操作malloc永远不能隐式创建类类型 的对象T。在此示例中,我们打算ptr指向具有 10 个类型元素的数组对象的初始元素T。基于这个假设,ptr++就会有一个有效的行为。根据 [intro.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++;
Run Code Online (Sandbox Code Playgroud)
我们应该先获取数组指针并使用该指针值来获取初始元素指针值?这些过程对于使程序格式良好是必要的吗?
我认为第一个例子完全有效,但毫无意义。malloc 返回的数组尚未初始化任何对象。虽然我认为您可以形成指向每个对象的指针并迭代数组,但您不得在任何时候取消引用该指针。
在我看来,这里唯一缺少的是使用放置新或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++;
}
Run Code Online (Sandbox Code Playgroud)
数组中的对象只能使用指针运算或者数组索引来构造ptr[i],相当于*(ptr + i),所以与 基本相同p++。如果您的初始示例是 UB,那么上面的 constructor_at 调用也将是 UB。解决这个问题的唯一方法是将 malloc 的返回视为字节数组,并在每个 sizeof(T) 字节处调用 construct_。我希望在构建之后,可以将数组转换为正确的类型。但这是愚蠢的,我希望没有人能找到一个必要的理由。
总的来说,如果你的例子是非法的,那么你将如何设法实现 new() 本身?
| 归档时间: |
|
| 查看次数: |
387 次 |
| 最近记录: |