C++ 更改不允许使用动态分配的数组作为存储提供程序?

C++23 changes disallow using dynamically allocated array as storage provider?

提问人:JMC 提问时间:9/1/2023 更新时间:9/1/2023 访问量:106

问:

这是使用动态无符号 char 数组作为 T 型的“存储”的基本示例。

unsigned char* storage = new unsigned char[sizeof(T)];
T* foo = new(storage) T; // line 2
// use *foo somehow
foo->~T(); //destroy our foo

delete[] storage; // Undefined as of C++23? How else to do it?

在第 2 行之后,数组本身仍然处于活动状态,因为它为嵌套在数组中的 T 提供存储,但数组元素现在应该超出生存期,因为它们的存储已被 T 重用,并且 T 不嵌套在它们中,只嵌套在数组本身中。

但是,在使用完这个数组后,我们如何使用指针删除它,它是指向生命周期外第一个元素的指针?foo

直到(排除)C++23 [basic.life]/6 建议允许或至少不禁止在表达式中使用此指针:delete

如果出现以下情况,程序具有未定义的行为: (6.1) 对象将属于或曾经是具有非平凡析构函数的类类型,并且指针用作删除表达式的操作数,

这不适用于 IT'S NOT A CLASS TYPE。但是,从 C++23 开始,这句话改unsigned char

如果出现以下情况,程序具有未定义的行为:(6.1) 指针用作删除表达式的操作数,

现在包括 .unsigned char

这是否意味着不再可能以这种方式使用 char-array 作为存储?

到目前为止,我对该标准的研究给了我 3 种可能的质疑:

  1. 它可能与现在被定义为无符号字符数组的“对象表示”有关,这意味着指针现在可能指向一个新的无符号字符,这是“对象表示”的一部分,因此仍然有效,或者

  2. 整个 basic.life/6 paragrah 不应该在这里适用,因为它说:

在对象占用的存储被重用之前

这已经发生了,尽管这种重用再次通过调用 或~T()

  1. 考虑到 -expression 无论如何都不允许我们指定所需的对齐方式,这甚至有可能从未适用于使用 -expression 创建的数组吗?newnew

以下哪一项(如果有的话)可能是正确的?

C++ 内存-管理 语言-律师 放置-新增

评论

0赞 Ben Voigt 9/1/2023
可以说,您确定的项目符号不适用,因为上面的段落禁止“在释放存储之前”执行任何操作,并且确实释放了存储,而不是在释放存储之前订购的。delete[] storage;
0赞 Ben Voigt 9/1/2023
如果您愿意,您还可以调用 placement new ,这将为自动(琐碎的)析构函数调用完美地备份所有内容,这些调用发生在现在,它以一种不令人满意的方式“未重用”。new (storage) unsigned char[original_size];delete[] storage;p->~T()
0赞 JMC 9/1/2023
你的意思是在打电话之前在现有中新放置另一个吗?有趣的解决方案。但是,我不明白您的第一条评论。在释放存储之前,代码段中的哪些操作是被禁止的?你是说第 2 行和第 3 行吗?unsigned char[]unsigned char[]delete[]
1赞 Ben Voigt 9/1/2023
对第一个问题(另一个)是肯定的,尽管它不是“在现有”的问题中。那么不,我的意思是你正在解释 [basic.life]/6.1 以禁止将指针作为 delete 的操作数传递,但它并没有无条件地禁止这样做。它禁止在特定时间间隔内传递要删除的指针,从对象生存期结束时开始,到释放存储时结束。 该时间间隔的终点(存储释放)。[basic.life]/6 使用单词“before”,表示间隔处于打开状态,不包括其终结点。unsigned char[]delete[] storage
0赞 Language Lawyer 9/2/2023
你能 github.com/cplusplus/CWG/issues 吗?(被 cplusplus.github.io/CWG/issues/2625.html 打破)

答: 暂无答案