Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.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++ 取消引用悬空指针是未定义的行为吗?_C++_Language Lawyer_Undefined Behavior - Fatal编程技术网

C++ 取消引用悬空指针是未定义的行为吗?

C++ 取消引用悬空指针是未定义的行为吗?,c++,language-lawyer,undefined-behavior,C++,Language Lawyer,Undefined Behavior,我在标准中找不到该程序未定义的地方: #include <iostream> int main() { int *p; { int n = 45; p = &n; } std::cout << *p; } #包括 int main() { int*p; { int n=45; p=&n; } std::cout由于措辞的原因,我不能100%确定,但3.8/6似乎涵盖了这一点(我认为这种解释是正确

我在标准中找不到该程序未定义的地方:

#include <iostream>

int main() 
{
    int *p;
    {
        int n = 45;
        p = &n;
    }
    std::cout << *p;
}
#包括
int main()
{
int*p;
{
int n=45;
p=&n;
}

std::cout由于措辞的原因,我不能100%确定,但3.8/6似乎涵盖了这一点(我认为这种解释是正确的原因是因为3.8/5中的非规范性示例,
//未定义的行为,*pb的寿命已结束
):

…在对象的生命周期结束后,在重用或释放对象占用的存储之前,可以使用引用原始对象的任何glvalue,但只能以有限的方式使用。如果:


那么第一个项目就是罪魁祸首:
对这样一个glvalue应用左值到右值的转换(4.1)
:此转换必须在调用
操作符时发生,因此首先根据3.7.3自动存储持续时间释放对象的存储:

块作用域变量是否显式声明为寄存器 声明的static或extern具有自动存储持续时间 对于这些实体,将持续到创建它们的块为止 出口

3.8对象寿命开始

在对象的生存期开始之前但在存储之后 对象将占用的位置已分配,或者 对象的生存期已结束,在 对象被重用或释放,引用 可以使用对象将位于或曾经位于的存储位置 但只有有限的方式


因此,取消引用指向存储释放的变量的指针会导致UB

这当然是未定义的行为(根据常识和标准的措辞)

就标准而言,3.8/5对于什么是允许的,什么是不允许的是相当具体的:

[…]在对象的生命周期结束后,在重新使用或释放对象占用的存储之前,可以使用指向对象将要或曾经所在的存储位置的任何指针,但只能以有限的方式[…]使用指针,就像指针属于void*类型一样, 定义明确
允许间接[…]如下所述[…]。如果

-…
-[…]用作
静态\u cast
的操作数,除非转换是指向cv
void
,或指向cv
void
的指针,然后指向cv
char
或cv
无符号char

-[…]用作
动态\u cast的操作数

根据3.7.3/1,对象的存储在作用域的末尾结束(在实践中,这很可能不是真的,堆栈帧可能会在函数末尾重置,但在形式上就是这样)。因此,取消引用不会在生存期结束后发生,而是在释放存储之前发生。它发生在释放存储之后。
因此,您无论如何都可以取消引用指针的特殊条件不适用(对于具有相同前提条件的任何类似段落,如3.8/6,也是如此)

此外,假设上一段不是真的,则只允许将指针取消引用为cv
void*
,或将其转换为cv
char
(有符号或无符号)在取消引用之前。换句话说,不允许您将指向的
int
视为一个
int
。如3.8/5中所述,
int*
在对象的生存期之后实际上只是一个
无效*
。这意味着将其作为
int*
取消引用相当于这样做强制转换(不明确,但仍然)


有人真的希望这种尝试会产生一个错误,但我想这对编译器来说是一个很难检测到的错误。指针本身是有效的,并且是通过获取有效对象的地址安全地派生出来的,这可能几乎不可能进行诊断。

*p
是一个glvalue。我相信代码
可以
 p
仍将指向
n
所在的内存位置,但您无法知道将出现什么。@mstbaum以及这与问题的关系如何?@remyabel(我之前删除的注释询问“无法预测结果”是否暗示UB。)也许我不清楚什么是未定义的行为。我的推理可能与mstbaum的类似,因为我们不知道记忆中的位置,所以我们无法预测结果。这还不够吗?我需要在标准中查找它以确定吗?@Egenchris这些答案似乎都没有引用它是否为UB(他们只是在没有证据的情况下宣布它是或不是)具有不确定值的对象有一个不可预测的值。你会说行为是未定义的吗?不,因为标准要求它。不知道这在标准中的什么位置,但由于n位于堆栈中,人们会认为内存将被“释放”当它超出范围时。此外,我对3.7.3(“自动存储持续时间”)的理解是,在块退出后,对象占用的存储不需要存在。您能否确定存储何时被重用或释放,因为这取决于该短语。特别是因为这需要在之前发生。我想说“存储被释放”发生在变量超出范围时,因此这不适用(请参见3.7.3/1)。该部分试图讨论诸如placement delete和newRe等情况。更新版本“Soke a glvalue”仍然指“重用或释放对象占用的存储之前”