7

我知道当对象从函数按值返回时,它们的复制构造函数被调用。如果一个类有一个已删除的复制构造函数,则按值返回将失败。

struct X {
    X(const X &) = delete;
};

X f() {
   return X{};
}

error: call to deleted constructor of 'X'

C++11 为我们提供了扩展初始化器。我在 SO 帖子的某个地方读到这个

X f() {
    return {};
}

是相同的

X f() {
    return X{};
}

那么为什么下面的代码没有给我一个错误?它通过了,我什至可以在 main 中调用该函数:

struct D {
   D(const D &) = delete;
};

D f() { return {}; }

int main()
{
   f();
}

这是一个演示。没有错误报告。我觉得这很奇怪,因为我认为应该调用复制构造函数。谁能解释为什么没有给出错误?

4

1 回答 1

12

我在 SO 帖子的某处读到这个 ​​[...] 与 [...]

他们错了。它们相似,但不一样。

通过使用支撑初始化列表,您可以就地初始化返回值。如果您创建一个临时文件,那么您所做的是创建临时文件,然后将其复制到返回值中。任何有价值的编译器都会忽略它,但复制构造函数仍然必须是可访问的。

但是由于花括号初始化列表就地初始化了返回值,因此您不需要访问复制构造函数。

根据标准,第 6.6.3 节,p2:

带有花括号初始化列表的 return 语句通过指定初始化列表中的复制列表初始化 (8.5.4) 初始化要从函数返回的对象或引用。

请注意,“复制列表初始化”与“复制初始化”不同;它不进行任何复制,因此不需要可访问的复制构造函数。“复制列表初始化”和“直接列表初始化”之间的唯一区别是前者会阻塞explicit构造函数。

于 2013-03-10T22:20:14.010 回答