22

以下代码在 Visual C++ 2013 中编译良好,但在 GCC 或 Clang 下编译失败。

哪个是对的?
通过隐式转换返回对象时是否需要可访问的复制构造函数?

class Noncopyable
{
    Noncopyable(Noncopyable const &);
public:
    Noncopyable(int = 0) { }
};

Noncopyable foo() { return 0; }

int main()
{
    foo();
    return 0;
}

海合会:

error: 'Noncopyable::Noncopyable(const Noncopyable&)' is private
  Noncopyable(Noncopyable const &);
  ^
error: within this context
 Noncopyable foo() { return 0; }

铛:

error: calling a private constructor of class 'Noncopyable'
Noncopyable foo() { return 0; }
                    ^
note: implicitly declared private here
        Noncopyable(Noncopyable const &);
        ^
warning: C++98 requires an accessible copy constructor for class 'Noncopyable' when binding a reference to a temporary; was private [-Wbind-to-temporary-copy]
Noncopyable foo() { return 0; }
                           ^
note: implicitly declared private here
        Noncopyable(Noncopyable const &);
        ^
4

3 回答 3

15

当您return使用表达式时,会创建一个返回类型的临时对象,使用该表达式进行初始化,然后将其移动(或复制,如果移动不是一个选项)到返回值中。因此,您需要一个可访问的副本或移动构造函数。

但是,可以使用花括号列表直接初始化返回值。所以以下工作:

Noncopyable foo() { return {0}; }

现场示例中的类似情况。

于 2014-06-16T08:10:57.323 回答
5

12.8 复制和移动类对象[class.copy]

1/可以通过两种方式复制或移动类对象:通过初始化(12.1、8.5),包括用于函数参数传递(5.2.2)和用于函数值返回(6.6.3);[...]

6.6.3 中的 return 语句 [stmt.return]

2/ [...] 表达式的值被隐式转换为它出现的函数的返回类型。return 语句可能涉及临时对象的构造和复制或移动(12.2) [...]

12.2 临时对象 [class.temporary]

1/类类型的临时对象在各种上下文中创建:将引用绑定到纯右值 (8.5.3)、返回纯右值 (6.6.3)、创建纯右值的转换 (4.1、5.2.9、5.2.11、 5.4) , [...] 注意:即使没有调用析构函数或复制/移动构造函数,所有语义限制,例如可访问性(第 11 条)和函数是否被删除(8.4.3),都应满意。[...]

我认为 GCC 和 clang 是正确的——我什至会说任何时候你按值返回,返回类型必须有一个可访问的副本或移动构造函数。

逻辑是创建一个临时文件以将原始类型转换为新类型(intto Noncopyable),然后制作该临时文件的副本以返回该函数。

它本质上与以下内容相同:

Noncopyable foo() { return Noncopyable(0); }

您希望那里需要一份副本吗?我当然会。

于 2014-06-16T08:00:46.237 回答
4
  • 函数按值foo返回Noncopyable对象。因此,理论上必须调用复制构造函数。

  • 如果您使复制构造函数可用(即public)并打印一条消息以标记其调用,您将看到该消息未打印DEMO并且仅调用了重载的转换运算符。

  • 这是由于复制省略优化的事实。

  • 因此,不是重载的转换运算符需要复制构造函数,而是返回语句foo需要复制构造函数,因为您按值返回。

  • 最终,由于复制省略,复制构造函数不会被调用,但仍然必须可用。

于 2014-06-16T08:11:08.470 回答