可以使用指向在 "if" 语句中声明的变量地址的指针吗
Is it ok to use a pointer which point to the address of a variable declared inside "if" statement
可以使用指向在 "if" 语句中声明的变量地址的指针吗?
例子如下:
...
int *pTest = 0;
if (...)
{
int x = 10;
pTest = &x;
}
else
{
int x = 100;
pTest = &x;
}
...
// use pTest
问题是指针的生命周期大于所指向的对象的生命周期。这闻起来很难闻,你应该重新考虑你要做什么。
简短的回答是使用该指针是不安全的。长答案更复杂。如果您以非常具体的方式执行此操作,您 可以 执行此操作,老实说,我认为您永远不应该这样做。指针 pTest 很可能指向相对于堆栈指针的位置。只要没有其他东西破坏该位置,您就可以安全地使用它。这就是它在某些情况下可能“起作用”的原因。也就是说,这里有一些可能导致失败的事情:
另一个变量可能占用相同的 space,因为一旦该变量超出范围,另一个变量可能占用相同的 space。这类似于使用已释放的内存。
编译器可能会对您的代码进行转换,假设它不依赖于未定义的行为(这是)。例如,这可能表明编译器只是优化了这一行:
pTest = &x;
编译器可能优化该特定行的原因是它得出结论,任何依赖于从那里读取该指针的代码都依赖于未定义的行为,因此(理想情况下)程序员知道这一点并且不会编写依赖于未定义行为的代码。然后优化器将得出结论,最有效的解决方案是什么都不做。这不会破坏任何不依赖于未定义行为的代码。
更新:我找到了 this relevant question。感谢那里的标准引用,我可以说确实有一段导致指针值在对象的生命周期结束时变得无效。此外,对具有无效值的指针执行 lvalue-to-rvalue 转换是 implementation-defined 行为。
因此,我下面的答案最终应该改为implementation-defined。这意味着您的实施需要记录在执行此 lvalue-to-rvalue 转换时将执行的操作(如果这对您很重要)。
旧答案
如果您对 use 的定义意味着 lvalue-to-rvalue 转换(例如,打印值,将值复制到另一个指针,而不是取消引用它¹),我认为这符合标准。
[cov.lval]/3.3-3.4:
Otherwise, if the object to which the glvalue refers contains an invalid pointer value ([basic.stc.dynamic.deallocation],
[basic.stc.dynamic.safety]), the behavior is implementation-defined.
Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
An implementation may have relaxed pointer safety, in which case the validity of a pointer value does not depend on whether it is a
safely-derived pointer value. Alternatively, an implementation may
have strict pointer safety, in which case a pointer value referring to
an object with dynamic storage duration that is not a safely-derived
pointer value is an invalid pointer value unless the referenced
complete object has previously been declared reachable
([util.dynamic.safety]).
因此,如果我们有严格的指针安全性,它仍然有效 - 这部分不会使其无效,因为它不引用具有动态存储持续时间的对象。
简而言之,我声称在 lvalue-to-rvalue 转换的上下文中使用它是安全的。如果标准中有另一段使它的值无效,因为 referred-to 对象不再存在,或者 "the value contained in the object indicated by the glvalue" 有一些模糊的问题,我很乐意看到它。
¹:在这个一般领域有一些很好的讨论 here。我简化了这部分,因为 *p
的大多数用途都是未定义的行为。
如果您使用 "new" 将内存分配给变量 x 并将指针指向它,那就没问题了。因为当变量 x 的范围结束时(如外部 if),x 的 VALUE 仍将保留在堆上(分配给您的程序的动态内存)并且您的指针仍将指向某个有效值。但在您的情况下,由于分配给变量 x 的内存不是动态分配的,所以一旦 x 的范围在其 if 块之外结束,x 的 VALUE 也会消失,因此在这种情况下,指针现在不指向变量的值,而是现在指向一些垃圾值
可以使用指向在 "if" 语句中声明的变量地址的指针吗? 例子如下:
...
int *pTest = 0;
if (...)
{
int x = 10;
pTest = &x;
}
else
{
int x = 100;
pTest = &x;
}
...
// use pTest
问题是指针的生命周期大于所指向的对象的生命周期。这闻起来很难闻,你应该重新考虑你要做什么。
简短的回答是使用该指针是不安全的。长答案更复杂。如果您以非常具体的方式执行此操作,您 可以 执行此操作,老实说,我认为您永远不应该这样做。指针 pTest 很可能指向相对于堆栈指针的位置。只要没有其他东西破坏该位置,您就可以安全地使用它。这就是它在某些情况下可能“起作用”的原因。也就是说,这里有一些可能导致失败的事情:
另一个变量可能占用相同的 space,因为一旦该变量超出范围,另一个变量可能占用相同的 space。这类似于使用已释放的内存。
编译器可能会对您的代码进行转换,假设它不依赖于未定义的行为(这是)。例如,这可能表明编译器只是优化了这一行:
pTest = &x;
编译器可能优化该特定行的原因是它得出结论,任何依赖于从那里读取该指针的代码都依赖于未定义的行为,因此(理想情况下)程序员知道这一点并且不会编写依赖于未定义行为的代码。然后优化器将得出结论,最有效的解决方案是什么都不做。这不会破坏任何不依赖于未定义行为的代码。
更新:我找到了 this relevant question。感谢那里的标准引用,我可以说确实有一段导致指针值在对象的生命周期结束时变得无效。此外,对具有无效值的指针执行 lvalue-to-rvalue 转换是 implementation-defined 行为。
因此,我下面的答案最终应该改为implementation-defined。这意味着您的实施需要记录在执行此 lvalue-to-rvalue 转换时将执行的操作(如果这对您很重要)。
旧答案
如果您对 use 的定义意味着 lvalue-to-rvalue 转换(例如,打印值,将值复制到另一个指针,而不是取消引用它¹),我认为这符合标准。
[cov.lval]/3.3-3.4:
Otherwise, if the object to which the glvalue refers contains an invalid pointer value ([basic.stc.dynamic.deallocation], [basic.stc.dynamic.safety]), the behavior is implementation-defined.
Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
An implementation may have relaxed pointer safety, in which case the validity of a pointer value does not depend on whether it is a safely-derived pointer value. Alternatively, an implementation may have strict pointer safety, in which case a pointer value referring to an object with dynamic storage duration that is not a safely-derived pointer value is an invalid pointer value unless the referenced complete object has previously been declared reachable ([util.dynamic.safety]).
因此,如果我们有严格的指针安全性,它仍然有效 - 这部分不会使其无效,因为它不引用具有动态存储持续时间的对象。
简而言之,我声称在 lvalue-to-rvalue 转换的上下文中使用它是安全的。如果标准中有另一段使它的值无效,因为 referred-to 对象不再存在,或者 "the value contained in the object indicated by the glvalue" 有一些模糊的问题,我很乐意看到它。
¹:在这个一般领域有一些很好的讨论 here。我简化了这部分,因为 *p
的大多数用途都是未定义的行为。
如果您使用 "new" 将内存分配给变量 x 并将指针指向它,那就没问题了。因为当变量 x 的范围结束时(如外部 if),x 的 VALUE 仍将保留在堆上(分配给您的程序的动态内存)并且您的指针仍将指向某个有效值。但在您的情况下,由于分配给变量 x 的内存不是动态分配的,所以一旦 x 的范围在其 if 块之外结束,x 的 VALUE 也会消失,因此在这种情况下,指针现在不指向变量的值,而是现在指向一些垃圾值