“T const&t = C().a;”是否有效?延长“a”的寿命?
给出了以下场景,将其解释为 C++0x 代码:
struct B { };
struct A { B b; };
int main() {
B const& b = A().b;
/* is the object still alive here? */
}
Clang 和 GCC(截至 2011/02 的主干版本)的行为不同:Clang 延长了生命周期。 GCC 将 B
移动到一个新的临时对象,然后将引用绑定到该新的临时对象。
我找不到任何一种行为可以从标准的措辞中推导出来。表达式A().b
不是临时的(参见5.2.5)。有人可以向我解释以下内容吗?
- 期望的行为(委员会的意图)
- 您从 FDIS 获得的行为
谢谢!
The following scenario is given, to be interpreted as C++0x code:
struct B { };
struct A { B b; };
int main() {
B const& b = A().b;
/* is the object still alive here? */
}
Clang and GCC (trunk version as of 2011/02) behave differently: Clang lengthens the lifetime. GCC moves B
to a new temporary object, and then binds the reference to that new temporary.
I cannot find either behavior can be derived from the words of the Standard. The expression A().b
is not a temporary (see 5.2.5). Can anyone please explain the following to me?
- Desired behavior (the intent of the committee)
- The behavior as you derive it from the FDIS
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
N3126=10-0116 的 12.2 第 5 段指出:
,然后跟随四个特殊情况的列表(构造函数初始化器、引用参数、返回值、新初始化器)。
所以(在这个版本中)在我看来 clang 是正确的,因为您将引用绑定到临时对象的子对象。
编辑
认为对象的基本子对象这似乎也是唯一合理的行为。另一种方法意味着进行切片:
实际上,经过一些实验,g++ 似乎确实区分了成员子对象和基本子对象,但我不明白标准中在哪里进行了这种区分。以下是我使用的测试程序,可以清楚地看到两种情况的不同处理...(
B
是 Base,D
是 Derived,C
组成)。我用 g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 得到的输出是
在我看来,这要么是 g++ 中的错误,要么是 c++ 标准要求的错误,如果这确实是预期的行为或可能可接受的行为行为(但我必须说,我并没有真正考虑很多,这只是一种感觉,这种差异化有问题)。
In 12.2 paragraph 5 of N3126=10-0116 it's said that:
and then follows a list of four special cases (ctor-inizializers, reference parameters, returned value, new initializer).
So (in this version) seems to me that clang is correct because you're binding the reference to a subobject of a temporary.
EDIT
Thinking to the base sub-object of an object this also seems to be the only reasonable behavior. The alternative would mean doing a slicing in:
Actually after making a little experiment seems indeed that g++ differentiates between a member sub-object and a base sub-object, but I don't understand where this differentiation is made in the standard. The following is the test program I used and where it's clearly visible the different handling of the two cases... (
B
is Base,D
is Derived andC
is composed).The output I get with g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 is
In my opinion this is either a bug in g++ or a bug in what the c++ standard mandates if this is really the expected behavior or a possible acceptable behavior (but I must tell that I didn't really think about it a lot, this is just a feeling that something is wrong with this differentiation).
好吧,我对此做了一个 180 度的转变
在刷新了我对标准的了解之后,我不得不承认
预期
b
引用的对象在 const& 的作用域持续时间内保持活动状态(被扩展)可能是正确的。已初始化。我发现 GotW #88< /a> 对此有帮助的来源。我看不出
A().b
在结构或语义上与抱歉我可能造成的任何混乱有何不同。我在那里有点力不从心。
Okay, I'm doing a 180 degrees on this
After refreshing my knowledge of the standard, I have to admit
that it is probably right to expect the object referred to by
b
to remain alive (be extended) for the duration of scope in which the const& was initialized. I found GotW #88 a helpful source for this.I fail to see how
A().b
is structurally or semantically different fromSorry for any confusion I might have caused. I was a little out of my depth there.
临时对象根据其创建环境来区分。 (第 12.2 节“类类型的临时对象是在各种上下文中创建的……”)
对于由引用声明符创建的临时对象,第 12.2 节让我们参考第 8.5 节。 C++03 和 C++11 在 §8.5.3 中存在很大差异,但两者都明确支持您的代码。
C++03 说
讨论完全是从子对象的角度进行的,没有区分基类和成员。因此,如果不允许将引用绑定到成员,那么将成员绑定到基类也是如此,这排除了 ScopeGuard。
C++11 更详细,但指定
结合 6502 的答案,以及将引用绑定到以分号结尾的值的毫无意义,很明显,C++11继续支持这种行为。
Temporary objects are distinguished by the circumstances of their creation. (§12.2 "Temporaries of class type are created in various contexts…")
For temporaries created by a reference declarator, §12.2 refers us to §8.5. C++03 and C++11 differ greatly in §8.5.3, but both clearly support your code.
C++03 says that either
The discussion is entirely in terms of subobjects, not distinguishing base classes from members. So, if binding a reference to a member is disallowed, then so is binding a member to a base, which rules out ScopeGuard.
C++11 is more verbose, but specifies
Combined with 6502's answer, and the pointlessness of binding a reference to a value which ends at the semicolon, it is apparent that C++11 continues to support this behavior.
让我们看看(所有引用均针对 FDIS):
1) 5.2.3/2 表示
A()
是纯右值。2) 5.2.5/4 表示由于第 1) 点,
A().b
是纯右值。3) 8.5.3/5 表示
B const& b
直接绑定到A().b
而不创建临时文件。4) 12.2/5 表示临时绑定到引用的生命周期得到了延长。
所以至少 GCC 在这里是错误的。
Clang 是否正确或者是否是 UB 取决于临时对象的子对象本身是否是临时对象。我很确定答案应该是肯定的,但标准似乎对此事保持沉默。应该有人提交 DR 吗?
编辑:正如@6502所说,3.7.5表示子对象的生命周期是其完整对象的生命周期。Let's see (all references are to the FDIS):
1) 5.2.3/2 says
A()
is a prvalue.2) 5.2.5/4 says that
A().b
is a prvalue because of point 1).3) 8.5.3/5 says that
B const& b
binds directly toA().b
without creating a temporary.4) 12.2/5 says that the lifetime of a temporary bound to a reference is extended.
So it appears at least that GCC is wrong here.
Whether Clang is correct or if this is UB depends on whether the subobject of a temporary is itself a temporary. I'm quite sure the answer should be affirmative, but the Standard seems silent about the matter. Should someone submit a DR?
EDIT: As @6502 said, 3.7.5 indicates that the lifetime of a subobject is the lifetime of its complete object.