是否允许删除来修改其参数? [英] Is delete allowed to modify its parameter?

查看:90
本文介绍了是否允许删除来修改其参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个答案中, https://stackoverflow.com/a/704568/8157187 ,引用了Stroustrup:

In an answer, https://stackoverflow.com/a/704568/8157187, there is a quote from Stroustrup:

C ++明确允许删除的实现将零 左值操作数,我曾希望实现能够做到这一点, 但是这个想法似乎并没有在实施者中流行.

C++ explicitly allows an implementation of delete to zero out an lvalue operand, and I had hoped that implementations would do that, but that idea doesn't seem to have become popular with implementers.

但是,我未能在标准中找到此明确声明.当前标准草案(N4659)的一部分可以用这种方式解释:

However, I failed to find this explicit statement in the standard. There is a part of the current draft standard (N4659), that one may interpret this way:

6.7:

到达存储区域的持续时间结束时, 表示该指针任何部分地址的所有指针的值 存储区域变为无效的指针值(6.9.2).间接的 通过无效的指针值并传递无效的指针值 释放函数的行为不确定.的其他任何用途 无效的指针值具有实现定义的行为.

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values (6.9.2). Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

脚注:一些实现可能会定义复制无效的指针值会导致系统生成的运行时错误

Footnote: Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault

因此,在delete ptr;之后,ptr的值变为无效的指针值,并且使用此值具有实现定义的行为.但是,这并不表示允许ptr的值更改.

So, after a delete ptr;, ptr's value becomes a invalid pointer value, and using this value has implementation-defined behavior. However, it doesn't say that ptr's value is allowed to change.

这可能是一个哲学问题,如果一个人不能使用它的值,该如何确定它已经改变?

It might be a philosophical question, how can one decide that a value has changed, if one cannot use its value?

6.9:

对于任何琐碎的对象(基类子对象除外) 可复制的类型T,对象是否持有类型的有效值 T,组成对象的基础字节(4.4)可以复制到 char,unsigned char或std :: byte(21.2.1).43数组 该数组的内容被复制回该对象,该对象应 随后保留其原始值.

For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (4.4) making up the object can be copied into an array of char, unsigned char, or std::byte (21.2.1).43 If the content of that array is copied back into the object, the object shall subsequently hold its original value.

因此,将无效的指针值memcpy放入char数组似乎是有效的(取决于哪个语句是更强",6.7或6.9.对我而言,6.9似乎更强).

So, it seems, that it is valid to memcpy an invalid pointer value into a char array (depending on which statement is "stronger", 6.7 or 6.9. To me, 6.9 seems stronger).

这样,我可以检测到指针值已被delete更改:memcpy delete到char数组之前和之后的指针值,然后进行比较.

This way, I can detect, that the pointer value has been changed by delete: memcpy the pointer's value before and after the delete to char array, then compare them.

因此,据我所知,6.7不允许授予delete修改其参数的权限.

So, as I understand, 6.7 doesn't grant that delete is allowed to modify its parameter.

是否允许删除以修改其参数?

Is delete allowed to modify its parameter?

在此处查看评论: https://stackoverflow.com/a/45142972/8157187

这是不太可能的,但仍然可能是现实世界中的代码,这很重要:

Here's an unlikely, but still possible real-world code, where this matters:

SomeObject *o = ...; // We have a SomeObject
// This SomeObject is registered into someHashtable, with its memory address
// The hashtable interface is C-like, it handles opaque keys (variable length unsigned char arrays)

delete o;

unsigned char key[sizeof(o)];
memcpy(key, &o, sizeof(o)); // Is this line OK? Is its behavior implementation defined?
someHashtable.remove(key, sizeof(key)); // Remove o from the hashtable

当然,此代码段可以重新排序,因此它肯定是有效的代码.但是问题是:这是有效的代码吗?

Of course, this snippet can be reordered, so it becomes a surely valid code. But the question is: is this a valid code?

这是一个相关的思路:假设,一个实现确实定义了脚注所描述的内容:

Here's a related train of thought: suppose, that an implementation does define what footnote describes:

复制无效的指针值会导致系统生成的运行时错误

copying an invalid pointer value causes a system-generated runtime fault

6.9保证我可以memcpy()任何值.甚至是无效的.因此,在此理论实现中,当我memcpy()无效指针值(应该成功,6.9保证)时,在某种意义上,我不使用无效指针值,而仅使用其基础字节(因为它将生成一个无效字节).运行时错误,而6.9不允许这样做),因此6.7不适用.

6.9 guarantees that I can memcpy() any value. Even an invalid one. So in this theoretical implementation, when I memcpy() the invalid pointer value (which should succeed, 6.9 guarantees that), in a sense, I don't use the invalid pointer value, but only its underlying bytes (because it would generate a runtime fault, and 6.9 doesn't allow it), so 6.7 doesn't apply.

推荐答案

在删除之前,ptr的值有效.删除后,该值无效.因此,值改变了.有效值和无效值是互斥的-值不能同时有效和​​无效.

Before the deletion, ptr's value was valid. After the deletion, the value was invalid. Therefore the value changed. Valid values and invalid values are mutually exclusive -- a value cannot be simultaneously valid and invalid.

您的问题有一个基本的误解;您正在混淆这两个不同的概念:

Your question has a basic misconception; you're conflating these two different concepts:

  • 变量的值
  • 内存中变量的表示形式.

这两件事之间没有一一对应的关系.相同的值可以具有多个表示,并且相同的表示可以对应于不同的值.

There isn't a one-to-one correspondence between these two things. The same value may have multiple representations, and the same representation may correspond to different values.

我认为您的问题的要旨是: delete ptr;可以更改ptr的表示形式吗?.答案是是".您可以将已删除的指针存储到char数组中,检查字节,然后将它们全部查找为零值字节(或其他任何值).标准C ++ 14 [basic.stc.dynamic.deallocation]/4(或C ++ 17 [basic.stc]/4)对此进行了覆盖:

I think the gist of your question is: can delete ptr; change the representation of ptr?. To which the answer is "Yes". You could memcpy the deleted pointer into a char array, inspect the bytes, and find them all to be zero-valued bytes (or anything else). This is covered in the standard by C++14 [basic.stc.dynamic.deallocation]/4 (or C++17 [basic.stc]/4):

对无效指针值的任何其他使用均具有实现定义的行为.

Any other use of an invalid pointer value has implementation-defined behavior.

这是实现定义的,实现可以定义检查字节为零的字节.

It's implementation-defined and the implementation could define that inspecting the bytes gives bytes with value zero.

您的代码段依赖于实现定义的行为. 有效代码"不是标准所使用的术语,但是该代码可能不会从哈希表中删除预期的项目.

Your code snippet relies on implementation-defined behaviour. "Valid code" isn't terminology used by the Standard, but the code might not remove the intended item from the hash table.

如Stroustrup所暗示,这是一个故意的设计决定.一个示例用法是在调试模式下的编译器将删除的指针设置为特定表示形式,这样,如果随后使用删除的指针,则它可能引发运行时错误. 这是未初始化指针的一个示例.

As alluded to by Stroustrup, this is an intentional design decision. An example usage would be a compiler in debug mode setting deleted pointers to a particular representation, so that it can raise a runtime error if a deleted pointer is subsequently used. Here's an example of that principle in action for uninitialized pointers.

历史记录:在C ++ 11中,这种情况是未定义,而不是实现定义的.因此,使用删除的指针的行为与使用未初始化的指针的行为相同.在C语言中,释放内存的定义是将指向该内存的所有指针置于与未初始化的指针相同的状态.

Historical note: In C++11 this case was undefined, rather than implementation-defined. So the behaviour of using a deleted pointer was identical to the behaviour of using an uninitialized pointer. In the C language, freeing memory is defined as putting all pointers to that memory into the same state as an uninitialized pointer has.

这篇关于是否允许删除来修改其参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆