Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否允许delete修改其参数?_C++_Language Lawyer_C++17 - Fatal编程技术网

C++ 是否允许delete修改其参数?

C++ 是否允许delete修改其参数?,c++,language-lawyer,c++17,C++,Language Lawyer,C++17,在回答中,有一句来自Stroustrup的话: C++显式允许delete的实现将 左值操作数,我希望实现能做到这一点, 但这种想法似乎并没有受到实施者的欢迎 然而,我没有在标准中找到这个明确的声明。现行标准草案(N4659)中有一部分可以这样解释: 6.7: 当到达存储区域的持续时间结束时 所有指针的值,这些指针表示该文件任何部分的地址 存储区域变为无效指针值(6.9.2)。间接 通过无效指针值并传递无效指针值 对解除分配函数具有未定义的行为。任何其他使用 无效指针值具有实现定义的行为 脚注:

在回答中,有一句来自Stroustrup的话:

C++显式允许delete的实现将 左值操作数,我希望实现能做到这一点, 但这种想法似乎并没有受到实施者的欢迎

然而,我没有在标准中找到这个明确的声明。现行标准草案(N4659)中有一部分可以这样解释:

6.7:

当到达存储区域的持续时间结束时 所有指针的值,这些指针表示该文件任何部分的地址 存储区域变为无效指针值(6.9.2)。间接 通过无效指针值并传递无效指针值 对解除分配函数具有未定义的行为。任何其他使用 无效指针值具有实现定义的行为

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

因此,在
删除ptr之后
ptr
的值成为无效的指针值,使用此值具有实现定义的行为。但是,它并没有说允许更改
ptr
的值


这可能是一个哲学问题,如果一个人不能使用它的价值,他怎么能确定一个价值已经改变了

6.9:

对于任何对象(基类子对象除外)的 可复制类型T,无论对象是否持有类型为的有效值 T、 构成对象的底层字节(4.4)可以复制到 字符、无符号字符或std::byte(21.2.1)的数组。43如果 如果该数组的内容被复制回对象中,则该对象将 随后保持其原始价值

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

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

因此,据我所知,6.7不允许
delete
修改其参数

是否允许delete修改其参数

请查看此处的评论:


下面是一个不太可能但仍然可能出现的现实世界代码,这很重要:

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
当然,这个代码段可以重新排序,因此它肯定是有效的代码。但问题是:这是一个有效的代码吗


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

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


6.9保证我可以
memcpy()
任何值。甚至是一个无效的。因此,在这个理论实现中,当I
memcpy()
无效指针值(应该成功,6.9保证)时,从某种意义上说,我不使用无效指针值,只使用它的底层字节(因为它会生成运行时错误,而6.9不允许),因此6.7不适用于删除之前,
ptr
的值是有效的。删除后,该值无效。因此,值发生了变化。有效值和无效值是互斥的——值不能同时有效和无效

你的问题有一个基本的误解;您将这两个不同的概念混为一谈:

  • 变量的值
  • 内存中变量的表示形式
这两件事之间没有一一对应的关系。同一个值可能有多个表示,同一表示可能对应于不同的值


我想你问题的要点是:可以
删除ptr更改ptr的表示形式?。答案是“是”。您可以将已删除的指针memcpy到一个char数组中,检查字节,发现它们都是零值字节(或其他任何内容)。这在标准中由C++14[basic.stc.dynamic.deallocation]/4(或C++17[basic.stc]/4)涵盖:

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

它是实现定义的,实现可以定义检查字节会得到值为零的字节


您的代码段依赖于实现定义的行为。“有效代码”不是标准使用的术语,但代码可能不会从哈希表中删除所需的项

正如Stroustrup所暗示的,这是一个有意的设计决策。例如,使用调试模式的编译器将删除的指针设置为特定表示形式,以便在随后使用删除的指针时引发运行时错误。对于未初始化的指针,该原则的作用


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

为了让删除函数更新指针,它需要知道该指针的地址并进行更新。这需要额外的内存、很少的额外操作和编译器支持。在您的示例中看起来或多或少有些琐碎

现在想象一个函数链,它在参数中互相传递指针,只有最后一个函数会真正删除。在这种情况下要更新哪些指针?最后一个?全部的对于后者,需要创建指针的动态列表:

Objec *o = ...
handle(o);
void handle(Object *o){
   if (deleteIt) doDelete(0);
   else doSomethingElseAndThenPossiblyDeleteIt(o);
}
void doDelete(Object *o) {
    delete o;
}
因此,从理论上讲,如果允许delete修改它的参数,它将打开一个暖气罐,降低程序效率。是的
delete p;
// ...
delete p;
delete p; p = 0;
// ...
delete p;
SomeObject *o = ...;

void *orgO = o;
delete o;

someHashtable.remove(orgO);
// someHashtable.remove(o); o might be set to 0