当按值返回列表初始化的对象时,为什么不调用复制构造函数?

Why is the copy-constructor not called when returning by-value a list-initialized object?

本文关键字:为什么不 调用 复制 构造函数 对象 返回 列表 初始化      更新时间:2023-10-16

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

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

error: call to deleted constructor of 'X'

c++ 11提供了扩展初始化式。我在某个地方读到这个

X f() {
    return {};
}

相同
X f() {
    return X{};
}

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

struct D {
   D(const D &) = delete;
};
D f() { return {}; }
int main()
{
   f();
}

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

我在某个地方读到这篇文章[…][…]与[…]相同

他们错了。它们相似,但不相同。

通过使用带括号的init-list,您可以初始化返回值就地。如果你创建了一个临时变量,那么你所做的就是创建这个临时变量,然后将它复制到返回值中。任何称职的编译器都会忽略它,但是复制构造函数仍然必须是可访问的。

但是,由于大括号init-list会就地初始化返回值,因此不需要访问复制构造函数。

出自标准第6.6.3节p2:

带带括号的init-list的return语句,通过copy-list-initialization(8.5.4)从指定的初始化列表初始化要从函数返回的对象或引用。

注意"copy-list-initialization"与"copy-initialization"不同;它不做任何复制,因此不需要一个可访问的复制构造函数。"copy-list-initialization"answers"direct-list-initialization"的唯一区别是前者会阻塞explicit构造函数。