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++中写东西,