根据 C++,该程序在哪个确切的语句中表现出未定义的行为?标准?
(我知道应该避免返回对函数局部变量的地址/引用,并且程序永远不应该这样做。)
返回对局部变量/引用的引用是否会导致未定义的行为?或者,未定义的行为是否仅在稍后使用返回的引用(或“取消引用”)时发生?
即,下面的代码示例在什么确切的语句(#1
或 #2
或 #3
)处调用未定义的行为? (我已经将我的理论与每个理论一起写下来)
#include <iostream>
struct A
{
int m_i;
A():m_i(10)
{
}
};
A& foo()
{
A a;
a.m_i = 20;
return a;
}
int main()
{
foo(); // #1 - Not UB; return value was never used
A const &ref = foo(); // #2 - Not UB; return value still not yet used
std::cout<<ref.m_i; // #3 - UB: returned value is used
}
我有兴趣知道 C++ 标准在这方面具体规定了什么。
我想要 C++ 标准的引用,它基本上可以告诉我哪个确切的语句使该代码格式不正确。
欢迎讨论具体实现如何处理这个问题,但正如我所说,理想的答案将引用 C++ 标准中的参考文献,毫无疑问地澄清了这一点。
(I am aware of the fact that returning address/reference to a variable local to the function should be avoided and a program should never do this.)
Does returning a reference to a local variable/reference result in Undefined Behavior? Or does the Undefined Behavior only occur later, when the returned reference is used (or "dereferenced")?
i.e. at what exact statement (#1
or #2
or #3
) does code sample below invoke Undefined Behavior? (I've written my theory alongside each one)
#include <iostream>
struct A
{
int m_i;
A():m_i(10)
{
}
};
A& foo()
{
A a;
a.m_i = 20;
return a;
}
int main()
{
foo(); // #1 - Not UB; return value was never used
A const &ref = foo(); // #2 - Not UB; return value still not yet used
std::cout<<ref.m_i; // #3 - UB: returned value is used
}
I am interested to know what the C++ standard specifies in this regard.
I would like a citation from the C++ standard which will basically tell me which exact statement makes this code ill-formed.
Discussions about how specific implementations handle this are welcome but as I said an ideal answer would cite an reference from the C++ Standard that clarifies this beyond doubt.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当然,当引用首次初始化时,它是有效完成的,满足以下条件:
从函数返回的引用是一个xvalue:
这意味着以下内容不适用:
此外,即使我们将以下内容解释为执行新引用“对象”的初始化,裁判也是当时可能还活着:
但是,您对新引用的初始化
main
内的ref
明显违反了[C++11: 8.3.2/5]
。我找不到它的措辞,但按理说,执行初始化时函数作用域已退出。至少,标准中似乎没有关于此事的任何进一步说明,因此如果上述推理不充分,那么我们不得不得出结论,该标准在这件事上是含糊不清的。幸运的是,它在实践中影响不大,至少在主流中是这样。
Of course, when the reference is first initialised it is done so validly, satisfying the following:
The reference being returned from the function is an xvalue:
That means the following does not apply:
Additionally, even if we interpret the following to mean that an initialisation of a new reference "object" is performed, the referee is probably still alive at the time:
However, your initialisation of a new reference
ref
insidemain
quite clearly violates[C++11: 8.3.2/5]
. I can't find wording for it, but it stands to reason that the function scope has been exited when the initialisation is performed.At the very least, there does not appear to be anything further stated about the matter in the standard, so if the above reasoning is not sufficient then we have to conclude that the standard is ambiguous in the matter. Fortunately, it's of little consequence in practice, at least in the mainstream.
这是我对此事的不完整且可能不充分的看法:
引用的唯一特殊之处是在初始化时它们必须引用一个有效的对象。如果该对象稍后不再存在,则使用该引用是 UB,因此初始化另一个对现已失效的引用的引用也是如此。
下面更简单的示例提供了与您的问题完全相同的困境,我认为:
在#1处,
r
内的引用不再有效,但程序很好。只是不要阅读r
。在您的示例中,行 #1 没问题,而行 #2 则不行——这是因为原始行 #2 使用参数
调用
,正如所讨论的,这无法使用有效引用初始化函数参数变量,您编辑的版本A::A(A const &)
foo()A const & 也是如此。 a = foo();
。Here's my incomplete and possible insufficient view on the matter:
The only thing special about references is that at initialization time they must refer to a valid object. If the object later stops existing, using the reference is UB, and so is initializing another reference to the now-defunct reference.
The following much simpler example provides exactly the same dilemma as your question, I think:
At #1, the reference inside
r
is no longer valid, but the program is fine. Just don't readr
.In your example, line #1 is fine, and line #2 isn't -- that is because the original line #2 calls
A::A(A const &)
with argumentfoo()
, and as discussed, this fails to initialize the function argument variable with a valid reference, and so would your edited versionA const & a = foo();
.我会说#3。即使引用的对象已经超出范围,#2 本身也不会实际执行任何操作。这实际上并不是一个与标准相关的问题,因为它是连续犯下两个错误的结果:
要么孤立地具有定义的行为。该标准是否对在生命周期结束后使用对象的引用有任何规定是另一回事。
I would say #3. Alone, #2 doesn't actually do anything even though the referenced object is already out of scope. This isn't really a standards-related issue because it is the result of two mistakes made in succession:
Either in isolation has defined behavior. Whether the standard has anything to say regarding use of references to objects beyond the end of their lifetime is another matter.