Используют ли неявные преобразования типа класса конструктор копирования?

Следующая цитата из моей книги C++:

Когда мы используем прямую инициализацию, мы просим компилятор использовать обычную функцию сопоставления, чтобы выбрать конструктор, который лучше всего соответствует аргументам, которые мы предоставляем. Когда мы используем инициализацию копирования, мы просим компилятор скопировать правый операнд в создаваемый объект, преобразовав этот операнд при необходимости.

Для меня этот жирный бит вызывает некоторую двусмысленность. Звучит так, будто правый операнд преобразуется в тип класса, а затем, например, используется конструктор копирования;

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";
}

Должно быть продюсирование "Второй путь, Второй путь, Первый путь". Однако вместо этого он печатает "Второй путь, Второй путь". Из этого я бы сделал вывод, что он использует конструктор const char *, а не конструктор копирования. Я был бы в порядке с этим, кроме как позже это говорит...

Во время инициализации копирования компилятору разрешено (но не обязательно) пропускать конструктор копирования / перемещения и создавать объект напрямую. То есть компилятору разрешено переписывать

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

в

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

Однако, даже если компилятор пропускает вызов конструктора копирования / перемещения, конструктор копирования / перемещения должен существовать и быть доступным (например, не приватным) в этой точке программы.

Я не уверен, почему конструктор копирования даже нуждается в упоминании в этих примерах, не

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

всегда подразумевается, что конструктор const char * все равно используется? На самом деле, для меня не имеет смысла определять конструктор копирования, чтобы все вышеперечисленное работало. Но, увы, если я помещу конструктор "const A&" как private (остальное public), тогда моя программа не запустится. Почему конструктор копирования должен быть определен для неявных преобразований, которые даже не включают его? Какой конструктор использует "string null_book = "9-999-99999-9""?

1 ответ

Решение

string null_book = "9-999-99999-9"; средства string null_book = string("9-999-99999-9");,

Это использует const char * конструктор для создания временного объекта, а затем null_book это копирование / перемещение, созданное из временного объекта, а затем временный объект уничтожается.

(Конструкция копирования / перемещения означает, что конструктор перемещения используется, если он доступен; в противном случае - конструктор копирования).

Однако этот сценарий также имеет право на получение копии. Вы фактически процитировали спецификацию копии elision в своем вопросе, поэтому я не буду повторять ее.

Компилятор может выбрать использование одного и того же пространства памяти для обоих null_book и временный объект, и пропустить вызовы деструктора временного объекта и null_book конструктор копирования / перемещения.

В вашем случае компилятор действительно решил сделать это, поэтому вы не видите никакого вывода конструктора копирования.

Некоторые компиляторы позволяют отключить копирование, например, gcc / clang -fno-elide-constructors,

Подробнее о копировании elision

Другие вопросы по тегам