C++ 我是否可以新建[],然后强制转换指针,然后使用C+中的内置类型安全地删除[]+;?

C++ 我是否可以新建[],然后强制转换指针,然后使用C+中的内置类型安全地删除[]+;?,c++,visual-c++,memory-management,undefined-behavior,C++,Visual C++,Memory Management,Undefined Behavior,在我的代码中,我有效地做到了以下几点: wchar_t* buffer = new wchar_t[size]; // bonus irrelevant code here delete[] reinterpret_cast<char*>( buffer ); wchar\u t*buffer=新的wchar\u t[size]; //不相关的代码在这里 删除[]重新解释转换(缓冲区); 所讨论的类型都是内置的,因此它们都有简单的析构函数。在VC++中,上述代码正常工作-new[

在我的代码中,我有效地做到了以下几点:

wchar_t* buffer = new wchar_t[size];
// bonus irrelevant code here
delete[] reinterpret_cast<char*>( buffer );
wchar\u t*buffer=新的wchar\u t[size];
//不相关的代码在这里
删除[]重新解释转换(缓冲区);
所讨论的类型都是内置的,因此它们都有简单的析构函数。在VC++中,上述代码正常工作-
new[]
只需分配内存,然后
delete[]
只需释放内存


在C++中是否可以接受?这是未定义的行为吗?

这是未定义的行为,因为
delete[]
调用了错误的析构函数。但是,
wchar\u t
char
是POD,因此它们没有专用的析构函数,所有
delete[]
所做的都是调用堆实现来释放指针。因此,它最有可能工作,没有字节丢失。但是严格来说,它仍然没有定义。

delete[]操作符在内部使用某种形式的循环来破坏数组的元素。如果元素是不同的对象,将使用不同的析构函数——这可能会导致未定义的行为。由于是wchar和char(基本类型),它可能不会导致任何不希望的行为

警告:如果你继续阅读,后果自负!!对未来未定义行为的粗略描述。这仅用于教育目的。

示例1:

如果您有两个大小相同的对象,并且它们的析构函数所做的只是将内存归零,那么它可能不会导致欠可寻址行为

示例2:

然而,如果您有两个对象,其中一个类型封装了一个4字节的资源句柄,另一个有两个这样的元素,并且您将后者的数组强制转换为单数形式,那么您将泄漏数组的一半句柄。情况如下:

…2:[1 | 2][1 | 2]免费

其中“2:”表示数组的大小。向下广播后,编译器将生成一个删除,该删除将数据视为:

…2:[1][1]免费

因此,在自由之后,事情会是这样的:


我最初的想法是这是一种未定义的行为

5.3.5/3:“在第二个备选方案(删除数组)中,如果动态 要删除的对象的类型 不同于它的静态类型 行为是未定义的

脚注73写道,“这意味着不能使用
void*
类型的指针删除对象,因为没有
void
类型的对象。”

可以说,您示例中的对象没有动态类型,因为1.3.3中“动态类型”的定义提到了“最派生的对象”,而1.8/4中“最派生的对象”的定义是关于类类型的对象。因此我一直在寻找:

5.2.10/3:“[重新解释]可能产生,也可能不产生陈述 “与原值不同”

5.3.5/2:“
delete
的操作数值应为指针值 这是由以前的数组导致的 新表达”

我不确定重新解释\u强制转换是否会产生与输入相同的指针值。可能是我还没有找到的其他标准位清除了它。我不会调用此代码“OK”,除非找到明确声明,如果重新解释\u强制转换指针,结果是相同的“指针值”如前所述,通过将其传递给delete[],您将从new[]传递“指针值”

5.2.10/7:“除了[在某些指针类型之间]和 返回到其原始类型将生成 原始指针值,是 这样的指针转换是不正确的 未指明”

这对我来说似乎是个坏消息——很明显,这并不是说强制转换产生了相同的值,只是一对反复的强制转换产生了相同的值。这对我来说意味着允许单个cast产生不同的值,但它只是暗示,而不是明确的。这是“如果标准没有说明行为,那么行为是未定义的”规则的常见问题。仅仅因为它没有在我使用索引可以找到的任何段落中声明它,并不意味着它没有在其他地方声明它


我们知道,在实践中,我们可以将内容强制转换为unsigned char*以检查其字节,或者void*以使用memcpy复制pod,因此必须保证有一些强制转换可以创建别名。您可能会认为,如果您的实现确实使用某些强制转换创建别名,那么您正在传递从new[]获得的“相同值”。但我仍然不确定这是否足以删除[]。我想我遗漏了一些重要的东西。

至少在我读到的时候,你有一个静态类型(指针的类型)与动态类型(指针指向的对象的真实类型)不同。在这种情况下,§5.3.5/3第二句适用于:

在第二个备选方案(删除数组)中,如果 要删除的对象与其静态类型不同,行为未定义


编辑:因为您显然想要分配一个“原始”内存缓冲区而不是对象数组,所以我建议使用
::operator new
而不是
new[]
。在这种情况下,您所做的是明确定义的,同时也为读者提供了明确的意图指示。

iso14882第5.2.10.3节:

reinterpret\u cast执行的映射是由实现定义的

iso14882第5.3.5.2节:

delete[]的操作数的值应是由上一个数组新表达式生成的指针值


换句话说,无论delete[]是否调用未定义的行为,都是由实现定义的。避开。

为什么要使用reinterpret\u cast?如果你在纯C++中写东西,