我找不到标准中说明这个程序未定义的地方:
#include <iostream>
int main()
{
int *p;
{
int n = 45;
p = &n;
}
std::cout << *p;
}
§3.8中关于对象生命周期的所有情况似乎都不适用于此。
我找不到标准中说明这个程序未定义的地方:
#include <iostream>
int main()
{
int *p;
{
int n = 45;
p = &n;
}
std::cout << *p;
}
§3.8中关于对象生命周期的所有情况似乎都不适用于此。
// undefined behavior, lifetime of *pb has ended
):an lvalue-to-rvalue conversion (4.1) is applied to such a glvalue,
:该转换必须在调用operator<<
的时候或最终在ostream
代码内部格式化整数值的读取点发生。45
吗? - user3920237n
具有自动存储期,参见[basic.stc.auto]p1:p
是一个无效指针,通过无效指针间接引用是未定义行为:n
的存储空间在第一个引号之后就已经超出了作用域,p
指向n
的存储空间,在第二个引号之后它成为了一个无效指针。你是想让我对此再具体一些吗? - Shafik Yaghmour*
需要一个值。p
所表示的对象包含一个[无效指针]值,但是这个表达式原本并没有指定该值。它属于错误的值类别。为了让 *
满意,应该采取什么措施?它如何与无效指针值交互? - Language Lawyer这绝对是未定义的行为(按照常识和标准的措辞)。
就标准而言,3.8/5非常明确关于允许和不允许的内容:
对象的存储在作用域结束时结束,根据3.7.3/1(实际上这很可能不是真的,在函数结束时堆栈帧可能会被重置,但是形式上是这样发生的)。因此,解引用不会在生命周期结束后发生,而是在存储释放之前发生。它发生在存储释放之后。[...] 在对象的生命周期结束后,在重新使用或释放该对象所占用的存储之前,可以使用任何指向对象所在位置的存储器的指针,但只能以有限的方式使用 [...]并且将指针用作void*类型是被定义的。
间接引用[...]是允许的[...]如下所述。如果程序:有未定义的行为:
- ...
- [...] 作为static_cast的操作数,除非转换为指向cv void的指针,或者转换为指向cv char或cv unsigned char的指针
- [...] 作为dynamic_cast的操作数
void*
或在解引用之前将其转换为cv char
(有符号或无符号)。换句话说,您不被允许像处理int
一样处理指向的int
。正如3.8/5所述,int*
在对象的生命周期结束后实际上只是一个简单的void*
。这意味着将其解引用为int*
等同于进行转换(虽然不是显式的,但仍然是)。希望这个尝试会产生错误,但我想这对编译器来说确实很棘手。指针本身是良好而活跃的,并且它已通过获取一个有效对象的地址进行了安全派生,这可能很难诊断。首先根据3.7.3 自动存储期,对象的存储将被释放:
在块范围内显式声明为register或未显式声明静态或外部变量具有自动存储期。这些实体的存储持续到创建它们的块退出。
接着根据3.8 对象生命周期
在对象的生命周期开始之前,但是在分配对象所占用的存储空间之后,或者在对象的生命周期结束之后并在重新使用或释放对象所占用的存储空间之前,任何指向对象将要或已经位于的存储位置的指针都可以被使用,但是只能进行有限的使用。
因此,对已释放存储空间中的变量进行指针解引用会导致未定义行为。
p
仍将指向n
所在的内存位置,但您无法知道那里会有什么。 - mstbaumbasic.stc.dynamic.deallocation/4
表明如果p
指向的动态存储已被释放,那么会产生未定义行为(UB),但对于自动存储没有提及任何内容。 - M.M