【问题标题】:List-initialization of const references to temporary objects对临时对象的 const 引用的列表初始化
【发布时间】:2013-06-29 17:20:26
【问题描述】:

当临时对象绑定到类的实例时,我发现下面使用 g++-4.8.1 的 2 个示例会出现不同的行为:

template <class T>
struct A
{
  A(T const& a) : b(a) { }

  T const& b;
};

template <class T>
struct B
{
  B(T const& a) : b{a} { }

  T const& b;
}

我发现,对于第一个示例,绑定的临时对象在 A 的实例的生命周期内持续存在,但对于 B 的实例而言并非如此。根据 C++11,这种行为是否正确标准?请指出标准的相关部分。

注意: AB,以及它们绑定的临时对象在表达式中实例化。在表达式结束时,它们连同它们绑定的临时对象一起被销毁,这就是为什么它们的生命周期应该与临时对象的生命周期相同。

编辑:这部分标准能否解释两个初始化之间的差异:

—否则,如果 T 是引用类型,则 T 引用的类型的纯右值临时是列表初始化的, 并且引用绑定到该临时文件。 [注:和往常一样,绑定会失败,程序 如果引用类型是对非常量类型的左值引用,则格式错误。 ——尾注]

【问题讨论】:

  • 您能否提供一个完整的例子?
  • 完整的例子是一个表达式模板类,会很长。用 ( ) 替换 { } 使表达式模板库工作。
  • @JoachimPileborg Example at ideone 证明 g++-4.7.2 为 B 创建了一个临时对象。
  • 这是GCC bug 50025

标签: c++ c++11


【解决方案1】:

这样的行为是不正确的。请参阅 8.5.4p3 第四条最后一个项目符号。一段时间以来,预标准草案就是这种情况,但在 C++11 中并非如此。

您似乎很困惑:在任何情况下都不应该创建一个临时的。两种情况都应该用另一个引用初始化一个引用。只有在第二种情况下,一些准标准草案说应该创建一个临时的并绑定到成员引用,而不是直接初始化引用。

(参见this list 中的第 27 号)。

【讨论】:

  • 但是在哪个文档中交换了项目符号? ISO-IEC 14882 已经更新了吗?
  • @user1095108 在 C++11 中交换
  • My copy - ISO/IEC 14882:2011(E) - from March 2012 在“...如果初始值设定项列表具有单个元素、对象或引用已初始化...”项目符号。从那时起它可能已经在编辑上得到修复,但至少 2011 年的第一次修订有错误的文本。
  • 这是Core Working Group issue 1288,根据N3377 Editor's Report 于2012 年2 月修复。
  • @Casey 然后我记错了。这是 C++11 后的修复。然而,这仍然应该在任何合理的 C++11 实现中实现。
【解决方案2】:

我发现,对于第一个示例,绑定的临时对象在 A 的实例的生命周期内持续存在,但对于 B 的实例而言并非如此。根据 C++11,这种行为是否正确标准?

B 的行为是正确的。但是A 的行为是错误的,因为临时不应该的生命周期一直持续到A 对象的生命周期(或B 的生命周期) B) 的情况。

但作为旁注,由于您将临时绑定到B 的成员,请注意!构造函数返回时临时不存在,也就是说成员所指的东西不存在!

【讨论】:

  • 但临时是表达式的一部分,并在创建它的完整表达式的末尾被销毁。临时变量的生命周期应该由表达式而不是构造函数来延长。
  • @user1095108:是的,是吗?我说不同意吗?
  • 构造函数返回后临时可能仍然存在,这就是我的意思。它不一定被销毁。
  • @user1095108:是的,学究式的说法。但实际上它并没有太大的区别,不是吗?您可以在同一个表达式中使用该成员(在它结束之前),但这不太可能,不是吗?
  • 这样的使用是表达式模板的核心。说Vector v(Vector(0, 0, 0) + Vector(1, 0, 0));
猜你喜欢
  • 2016-12-25
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 2019-06-17
  • 2010-12-14
  • 1970-01-01
相关资源
最近更新 更多