【发布时间】:2017-12-22 07:36:03
【问题描述】:
在https://stackoverflow.com/a/704568/8157187 的回答中,引用了 Stroustrup 的一句话:
C++ 明确允许删除的实现将 左值操作数,我曾希望实现能做到这一点, 但这个想法似乎并没有受到实施者的欢迎。
但是,我没有在标准中找到这个明确的声明。当前标准草案 (N4659) 的一部分可以这样解释:
6.7:
当一个存储区域的持续时间结束时, 表示任何部分地址的所有指针的值 存储区域变为无效的指针值 (6.9.2)。间接的 通过无效的指针值并传递无效的指针值 释放函数具有未定义的行为。任何其他使用 无效的指针值具有实现定义的行为。
脚注:某些实现可能会定义复制无效指针值会导致系统生成的运行时错误
所以,在delete ptr; 之后,ptr 的值变成了一个无效的指针值,并且使用这个值具有实现定义的行为。但是,并没有说ptr的值是允许改变的。
这可能是一个哲学问题,如果一个人不能使用它的值,怎么能确定一个值发生了变化?
6.9:
对于平凡的任何对象(基类子对象除外) 可复制类型 T,无论对象是否拥有类型的有效值 T,构成对象的底层字节(4.4)可以复制到 char、unsigned char 或 std::byte (21.2.1) 的数组。43 如果 该数组的内容被复制回对象中,该对象应 随后保持其原始值。
所以,看来,memcpy 将无效指针值放入 char 数组是有效的(取决于哪个语句“更强”,6.7 或 6.9。对我来说,6.9 似乎更强)。
这样,我可以检测到指针值已被delete 改变:memcpy 指针在delete 前后的值与char 数组相比,然后比较它们。
因此,据我了解,6.7 不允许 delete 修改其参数。
delete是否允许修改其参数?
在此处查看 cmets: https://stackoverflow.com/a/45142972/8157187
这是一个不太可能但仍然可能的实际代码,这很重要:
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
当然,这个 sn-p 可以重新排序,所以它成为一个肯定有效的代码。但问题是:这是一个有效的代码吗?
这是一个相关的思路:假设一个实现确实定义了脚注描述的内容:
复制无效的指针值会导致系统生成的运行时错误
6.9 保证我可以memcpy() 任何值。甚至是无效的。所以在这个理论实现中,当我memcpy() 无效指针值(应该成功,6.9 保证)时,从某种意义上说,我不使用无效指针值,而只使用它的底层字节(因为它会生成一个运行时错误,而 6.9 不允许),因此 6.7 不适用。
【问题讨论】:
-
"这可能是一个哲学问题,如果一个人不能使用它的价值,如何确定价值已经改变?"那句话上面的段落只是说明你不能取消引用指针,但是像
delete p; if (p==someOtherPOinter){}这样的东西应该没问题 -
@geza 由于使用它的结果是实现定义的,所以实现可以定义
if (p == nullptr)对于这个无效值是真的。 -
@geza 然后我遵循“好像”规则。如果所有操作的行为都与更改值一样,则允许实现更改它。
-
@geza 什么规则禁止更改 int 的内部位?据我所知,该实现甚至允许
int a = 0; /* test bits of 'a' now */; /* test bits of 'a' now*/每次有两个不同的位。 -
@geza 是的,正如我在回答中提到的,重要的是价值,价值和表示之间没有 1-1 对应关系(在任一方向上)。通常当然是为了节省内存用法,但一个例子是 1 的补码整数的负零,另一个广泛的情况是类型中未使用的位,我将我们在这个问题上讨论的部分解释为如果指针具有无效值,那么它独立于代表,即无论代表什么。也就是说,它仍然是一个无效值,并且在分配一个有效值之前会一直保持这种状态
标签: c++ language-lawyer c++17