сигнатура конструктора копирования c ++: имеет ли это значение

Моя текущая реализация использует множество конструкторов копирования с этим синтаксисом

MyClass::Myclass(Myclass* my_class)

Действительно ли это (функционально) отличается от

MyClass::MyClass(const MyClass& my_class)

и почему?

Мне сообщили, что первое решение не было истинным конструктором копирования. Однако внесение изменений подразумевает довольно много рефакторинга.

Спасибо!!!

6

Решение

Это отличается в том смысле, что первый не конструктор копирования, а конструктор преобразования. Конвертирует из MyClass* к MyClass,

По определению, конструктор копирования имеет одну из следующих подписей:

MyClass(MyClass& my_class)
MyClass(const MyClass& my_class)
//....
//combination of cv-qualifiers and other arguments that have default values

12,8. Копирование объектов класса

2) Не шаблонный конструктор для класса X является конструктором копирования, если его
Первый параметр имеет тип X&, const X&, летучий Х& или const volatile
Икс&и либо нет других параметров, либо все остальное
параметры имеют аргументы по умолчанию (8.3.6) .113) [Пример: X :: X (const
Икс&) и X :: X (X&, int = 1) являются конструкторами копирования.

РЕДАКТИРОВАТЬ: вы, кажется, путаете их.

Скажем, у вас есть:

struct A
{
A();
A(A* other);
A(const A& other);
};

A a;     //uses default constructor
A b(a);  //uses copy constructor
A c(&a); //uses conversion constructor

Они служат разным целям.

17

Другие решения

Первая версия не конструктор копирования. Просто как тот. Это просто еще один конструктор.

копия конструктор для класса X должен иметь подпись (X &, ...) или же (X const &, ...) или же (X volatile &, ...) или же (X const volatile &, ...)где все аргументы, кроме первого, имеют значения по умолчанию, если они присутствуют (и это не должен быть шаблон).


Тем не менее, вы должны очень тщательно подумать о том, почему вы нарушаете правило нуля: большинство хорошо разработанных классов не должны иметь любой пользовательский конструктор копирования, оператор назначения копирования или деструктор вообще, и вместо этого полагаться на хорошо разработанные элементы. Тот факт, что ваш текущий конструктор использует указатель, заставляет меня задуматься, правильно ли ваш код работает для чего-то вроде MyClass x = y; — стоит проверить.

7

Определенные языковые конструкции требуют конструктора копирования:

  • проходя по значению
  • возвращая по значению
  • инициализация в стиле копии (хотя в этом случае копия часто исключается)

Если язык требует копию, и вы предоставили конструктор копии, то его можно использовать (конечно, при условии, что cv-квалификации в порядке).

Поскольку вы не предоставили конструктор копирования, вы получите вместо этого сгенерированный компилятором конструктор копирования. Это работает путем копирования каждого члена данных, даже если это неправильно для вашего класса. Например, если ваш конструктор not-a-copy явно делает какие-либо глубокие копии или выделяет ресурсы, то вам нужно подавить сгенерированную компилятором копию.

Если сгенерированная компилятором копия работает для вашего класса, то ваш конструктор not-a-copy в основном безвреден. Я не думаю, что это особенно хорошая идея:

void some_function(const MyClass &foo);

MyClass *ptr = new MyClass();
const MyClass *ptr2 = ptr;
some_function(ptr); // compiles, but copies *ptr and uses the copy
MyClass bar(ptr2);  // doesn't compile -- requires pointer-to-non-const

Даже если предположить, что созданная компилятором копия не годится для вашего класса, внесение необходимых изменений не требует большого количества рефакторинга. Предположим, что ваш not-a-constructor фактически не изменяет объект, на который указывает его аргумент, поэтому после исправления подписи у вас есть:

MyClass::MyClass(const MyClass* my_class) {
// maybe treat null pointer specially
// do stuff here
}

Тебе нужно:

MyClass::MyClass(const MyClass& my_class) {
do_stuff(my_class);
}

MyClass::MyClass(const MyClass* my_class) {
// maybe treat null pointer specially
do_stuff(*my_class);
}

MyClass::do_stuff(const MyClass& my_class) {
// do stuff here
}

Вам также необходимо скопировать любой список инициализатора из старого конструктора в новый и изменить его так, чтобы my_class не указатель в новом.

Удаление старого конструктора может потребовать большого количества рефакторинга, так как вы должны отредактировать любой код, который его использует. Вам не нужно удалять старый конструктор, чтобы исправить все проблемы с конструктором копирования по умолчанию.

5

Первый пример не является конструктором копирования. Это означает, что когда вы предоставляете его, компилятор все еще предоставляет вам конструктор копирования по умолчанию с сигнатурой, эквивалентной

MyClass(const MyClass& my_class);

Если вы делаете что-то особенное с вашим конструктором, и предоставленный компилятором конструктор копирования не следует этой логике, вы должны либо реализовать конструктор копирования, либо найти способ отключить его.

1

Почему я хотел бы использовать конструктор копирования вместо конструктора преобразования?

Это может быть проблематично, если вы даете MyClass Объекты к некоторому коду, который ожидает, что ваш конструктор копирования будет действительным.

Это касается контейнеров STL. Например, если вы используете std::vector<MyClass>Вы должны знать, что векторам разрешено перемещать элементы для перераспределения, используя их конструкторы копирования.

Конструктор по умолчанию, предоставляемый компилятором, будет выполнять поверхностное копирование, вызывая конструкторы копирования каждого атрибута, делая простые копии для базового типа, такого как указатели. Если вам нужна какая-то форма глубокого копирования, вам придется правильно переписать конструктор копирования MyClass

1