2

这段代码

#include <iostream>

struct A
{
    A(int i) {std::cout << "int received\n";}
    A(A& a) {std::cout << "ref received\n";}
};

int main()
{
    int j = 5;
    A a = j;
}

意外引发以下编译器错误:

error: invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A'
note:   initializing argument 1 of 'A::A(A&)'
note:   after user-defined conversion: A::A(int)

当我删除第二个构造函数重载A(A& a)时,一切都按预期工作。我想编译器错误地调用了第二个构造函数而不是第一个。

为什么会这样?

我怎样才能让一个具有引用构造函数和右值构造函数的类和谐地工作?

我使用 GNU GCC。

注意:我还注意到一些奇怪的事情:显然,如果我用 替换该行A a = j;A a(j);一切都会按预期工作。void f(A a)然而,这并不令人满意,因为如果我试图从函数参数初始化对象(例如:调用with f(j)),它仍然不起作用。

4

1 回答 1

3

A a = j;执行复制初始化

直到 C++17,

ifT是类类型,且 cv 非限定版本的类型other不是T或派生自T,或者 ifT是非类类型,但类型other是类类型,用户定义的转换序列可以从该类型转换的otherto T(或从Tif派生的类型T是类类型并且转换函数可用)进行检查,并通过重载决议选择最佳的。转换的结果,prvalue temporary (until C++17) prvalue expression (since C++17)如果使用了转换构造函数,则用于直接初始化对象。The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

A有一个复制构造函数,将左值引用指向非 const,它不能绑定到从int. 即使是临时的A构造也可能被优化,复制构造函数必须可用。

使复制构造函数采用左值引用const(或添加移动构造函数)将解决该问题。

由于 C++17 由于强制复制省略,代码可以正常工作。

对象直接构建到存储中,否则它们将被复制/移动到。复制/移动构造函数不需要存在或可访问:

居住

另一方面,A a(j);执行直接初始化,直接a从初始化j,复制构造函数不参与。

于 2020-06-02T10:40:27.010 回答