【问题标题】:Is copy constructor still involved in copy initialization? [duplicate]复制构造函数是否仍然参与复制初始化? [复制]
【发布时间】:2022-07-06 12:42:24
【问题描述】:

考虑以下代码:

class Y {};
class X
{
public:
    X() { }
    X(const Y&) { }
    explicit X(const X&) { }
};

X f()
{
    return X();
}

int main()
{
    Y y;
    X x = y;
    f();
}

代码在return X(); 行出现错误(cannot convert from 'X' to 'X')。在我的理解中,这是因为X(X const&) 被声明为explicit 并且X(X const&) 被隐式“调用”以从X() 创建的对象中复制初始化返回的对象。由于存在复制省略,当X(const X&) 不是explicit 时,将直接使用X() 创建返回的对象。但是,explicit 关键字会停止代码,即使 X(X const&) 不会真正被调用,所以我的猜测是 explicit 关键字不关心是否存在复制省略。

在我的理解中,像X x = y; 这样的形式的复制初始化会首先尝试将y 转换为X 类型,然后将X 类型的对象从y 转换为x (所以X x = y; 做了类似X x{ X{y} } 的事情),并且由于存在复制省略,从y 转换而来的X 类型的对象将直接构造为x。

然后,我注释掉函数f()的定义和调用。我期待return X(); 发生同样的错误发生在X x = y,因为如果X x = y 执行类似X x{ X{y} } 的操作,如果没有复制省略,它会隐式调用explicit X(const X&),并且根据我对@ 的猜测987654352@关键字不关心是否有复制省略。

但是这次没有编译错误。所以,我猜X x = y 不会调用X(const X&),即使没有复制省略。我猜X x = y 只是对X(const Y&) 的隐式调用。


请问我的猜测是否正确?如果没有,有人可以告诉我哪里出错了,为什么explicit X(const X&) 在停止return X(); 时不会影响X x = y;?

【问题讨论】:

  • 主要编译器(clang、gcc、msvc)似乎都在编译代码,只要您使用适当版本的标准 (>=17) 进行编译:godbolt.org/z/f3neav6Ps

标签: c++ c++17 copy-constructor copy-initialization


【解决方案1】:

您的代码在更新的 C++17 中编译,因为强制复制省略不会检查可访问的复制/移动构造函数。

如果删除函数定义,无论 C++ 版本如何,代码都是有效的,因为在 X x = y; 中,x 是从临时 X 直接初始化的(即复制构造函数被“显式”调用,所以explicit 很好)。在 C++17 和更新版本中,这里首先没有临时的 X。

【讨论】:

  • @user17732522 我可以说,在 C++17 及之后的版本中,X x = y; 生成的代码与直接(尽管隐含地)调用 X(const Y&) 以构造 x 的代码相同吗?
  • @CPPL 在这种情况下是的,但通常不是,因为复制初始化不考虑 explicit 构造函数,并且存在更多不同的边缘情况。如果“生成相同的代码”是指实际编译的二进制代码,那么在这种情况下,在 C++17 之前和之后几乎肯定是相同的,因为即使在 C++17 之前,编译器也被允许省略中间临时代码编译器通常会这样做。它只需要检查复制构造函数是否可用(可访问且不可删除)。
  • 另外,您能否详细说明为什么从临时X 初始化x 显式调用复制构造函数? (C++17 之前)
  • @HolyBlackCat 这是公开的CWG issue 2327。目前没有指定省略。但我还是从评论中删除了那部分,因为这是一个不寻常的边缘案例,有规范问题,所以可能没有帮助。
  • @CPPL 因为语言规范在timsong-cpp.github.io/cppwp/n4140/dcl.init#17.6.2 中是这样说的。 (从技术上讲,它本身并不是真正的复制构造函数,但是从 X 直接初始化 X 通常会在构造函数的重载决议之后导致复制或移动构造函数。)并且指定了直接初始化还要考虑explicit 构造函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-08
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 2012-08-14
相关资源
最近更新 更多