【问题标题】:Does binding temporary to a reference require a copy constructor in C++?将临时绑定到引用是否需要 C++ 中的复制构造函数?
【发布时间】:2012-12-03 15:20:33
【问题描述】:

考虑以下代码:

class A {
  A(const A&);
 public:
  A() {}
};

int main() {
  const A &a = A();
}

此代码在 GCC 4.7.2 下编译良好,但在 Visual C++ 2010 上编译失败,并出现以下错误:

test.cc(8) : error C2248: 'A::A' : cannot access private member declared in class 'A'
        test.cc(2) : see declaration of 'A::A'
        test.cc(1) : see declaration of 'A'

那么在将临时对象绑定到引用时,是否必须要有一个可访问的复制构造函数?

这和我之前的问题有点关系:

Is there a way to disable binding a temporary to a const reference?

【问题讨论】:

  • 是的,copy ctor 是私有的,不是有意实现的。
  • 你试过A().<something>它可能需要复制构造函数从函数内部复制到返回值。
  • Visual C++ 2012 接受代码。
  • 是的,可能是编译器优化的问题
  • 被测试的编译器的版本号是应该包含在问题中的重要信息。无论如何,这看起来像是一个已修复的错误。如果可以的话,建议您升级到 Visual C++ 2012。 Visual C++ 2012 版本中修复了许多错误。

标签: c++ reference copy-constructor temporary


【解决方案1】:

那么在将临时对象绑定到引用时,是否必须要有可访问的复制构造函数?

发布 C++11 - 否
预 C++11 - 是的。


此代码在 GCC 4.7.2 中编译得很好,因为它符合 C++11 标准。

C++11 标准规定,当从prvalue 初始化 const 引用时,它必须直接绑定到引用对象,并且不允许创建临时对象。此外,不使用或不需要复制构造函数。

在 C++11 之前,规则有所不同。而这种行为(是否会调用复制构造函数)是由实现定义的。 C++03 允许在将 const 引用绑定到临时对象时调用复制构造函数,因此在 C++11 之后,复制构造函数需要可访问。 Visual C++2010 遵循 C++03 标准。

【讨论】:

  • “这种行为是由实现定义的”有点误导。实际复制与否由实现定义,但 C++03 标准需要一个可访问的复制构造函数。
  • “C++11 标准规定,当从纯右值初始化 const 引用时,它必须直接绑定到引用对象,并且不允许创建临时对象。”我们有点误导。仅当类型可以直接绑定时才成立。换句话说,规则不排除转换。
【解决方案2】:

C++03 标准的第 8.5.3.5 节声明这是实现定义的:

如果初始化表达式是右值,T2 是类类型,并且“cv1 T1”与“cv2 T2”引用兼容,则引用以下列方式之一绑定(选择由实现定义) :

-- 引用绑定到右值表示的对象(参见 3.10)或该对象内的子对象。

-- 创建一个“cv1 T2”[sic] 类型的临时对象,并调用构造函数将整个右值对象复制到临时对象中。引用绑定到临时对象或临时对象中的子对象。

无论复制是否实际完成,用于制作复制的构造函数都应该是可调用的。

看来这两种实现都符合C++03标准。

最后一句话有点混乱,但是按照我的阅读方式,这意味着实现可能会选择第二种方式,但仍然优化掉副本。在这种情况下,即使副本实际上并没有完成,复制构造函数也必须是可访问的,类似于返回值优化。

对于 C++11 标准,第二种方式不再是一种选择。

【讨论】:

  • C++03 已被 C++11 取代,C++11 中的规则也发生了变化。
  • 对,这就是我要找的。谢谢。
  • @Vaughn Cato:唯一的问题是您的最后一个陈述与您引用的标准中的最后一个陈述相矛盾。 IIUC 标准说,在这两种情况下都应该可以使用复制 ctor,因此 GCC 可能正在使用新标准中的规则或其错误。
  • @vitaut:我读它的方式,它只是意味着如果实现选择使用第二种方式,那么复制构造函数必须可用,即使副本实际上被省略了。也就是说,实现可以确定副本在逻辑上是必要的,但仍然优化掉实际的副本。
【解决方案3】:

Visual C++ 不正确;该标准并未指出复制构造函数必须可访问才能将const 引用绑定到临时对象。

【讨论】:

    猜你喜欢
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 2015-04-02
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多