隐式 class 类型转换是否使用复制构造函数?

Do implicit class-type conversions use the copy-constructor?

以下引用自我的 C++ 书籍:

When we use direct initialization, we are asking the compiler to use ordinary function matching to select the constructor that best matches the arguments we provide. When we use copy initialization, we are asking the compiler to copy the right-hand operand into the object being created, converting that operand if necessary.

对我来说,这个粗体字会产生一些歧义。这听起来像是将右侧操作数转换为 class 类型,然后使用复制构造函数,例如;

string s = "hello";

会变成...

string s = string("hello"); 

其中使用了拷贝构造函数。如果这是真的那么我的测试程序;

#include <iostream>
using namespace std;

class A{
public:
    A(const A& b): data(b.data) { cout << "The first way" << endl;}
    A(const char* c): data(c) { cout << "The second way" << endl;}
    string data;

};
int main(){
    A first("hello");
    A second = "sup";
}

应该生产 "The second way, The second way, The first way"。但是它会打印 "The second way, The second way"。由此我可以得出结论,它使用的是 const char* 构造函数而不是复制构造函数。我会接受这个,但后来它说...

During copy initialization, the compiler is permitted (but not obligated) to skip the copy/move constructor and create the object directly. That is, the compiler is permitted to rewrite

string null_book = "9-999-99999-9"; 

into

string null_book("9-999-99999-9");

However, even if the compiler omits the call to the copy/move constructor, the copy/move constructor must exist and must be accessible (e.g., not private) at that point in the program.

我不确定为什么在这些示例中甚至需要提及复制构造函数,

 string null_book = "9-999-99999-9"

always implicitly 意味着 const char* 构造函数无论如何都在使用?事实上,为了使上述工作正常,需要定义复制构造函数对我来说意义不大。但是唉,如果我把 "const A&" 构造函数设为私有(其余 public),那么我的程序将不会 运行。为什么必须为甚至不涉及它的隐式转换定义复制构造函数? "string null_book = "9-999-99999-9"" 使用什么构造函数?

string null_book = "9-999-99999-9"; 表示 string null_book = string("9-999-99999-9");.

这里使用const char *构造函数构造了一个临时对象,然后null_bookcopy/move从临时对象构造,并且然后临时对象被销毁。

(Copy/move构造表示如果可用则使用移动构造函数;否则使用复制构造函数。

然而,这种情况也适用于复制省略。您实际上在问题中引用了复制省略规范,因此我不再重复。

编译器可以选择对null_book和临时对象使用相同的内存space,并省略对临时对象析构函数和null_book copy/move 构造函数.

在你的情况下,编译器确实选择了这样做,这就是你看不到任何复制构造函数输出的原因。

一些编译器允许通过开关禁用复制省略,例如gcc/clang -fno-elide-constructors.

More info about copy elision