Ответ
Конструктор копирования вызывается для создания нового объекта как копии существующего объекта того же типа. Основные сценарии:
- Явная инициализация копией:
MyClass obj1; MyClass obj2(obj1); // Прямой вызов конструктора копирования MyClass obj3 = obj1; // Копирующая инициализация (также вызывает конструктор копирования) - Передача аргумента в функцию по значению:
void foo(MyClass param); // Функция принимает объект по значению MyClass obj; foo(obj); // При вызове `param` создаётся копированием `obj` - Возврат объекта из функции по значению (в определённых условиях):
MyClass createObject() { MyClass localObj; return localObj; // До C++17 мог вызываться конструктор копирования/перемещения. // Начиная с C++17, здесь гарантировано применяется оптимизация // (mandatory copy elision), и вызова конструктора не происходит. } - Инициализация элементов или базовых классов: При создании объекта, члены которого или базовые классы инициализируются другим объектом.
Практический пример:
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource defaultn"; }
Resource(const Resource&) { std::cout << "Resource copyn"; }
};
class MyClass {
Resource res;
public:
MyClass() { std::cout << "MyClass defaultn"; }
MyClass(const MyClass& other) : res(other.res) { // Вызов конструктора копирования Resource
std::cout << "MyClass copyn";
}
};
void byValue(MyClass c) { /* ... */ }
int main() {
std::cout << "--- Creating original ---n";
MyClass original;
std::cout << "n--- Copy initialization ---n";
MyClass copy = original; // Вызов MyClass::MyClass(const MyClass&)
std::cout << "n--- Passing by value ---n";
byValue(original); // Ещё один вызов конструктора копирования
return 0;
}
Важно: Современный C++ (C++11 и новее) стремится заменять копирование на перемещение (через конструктор перемещения) там, где это возможно, например, при возврате локальной переменной из функции.
Ответ 18+ 🔞
Э, слушай, давай разберём эту хрень с конструктором копирования, а то народ путается, как последний распиздяй. Представь, у тебя есть крутая тачка. Конструктор копирования — это когда ты делаешь её точную копию, чтоб на такой же кататься. Не воруешь, а именно копируешь, болт в болт.
Вот основные случаи, когда эта магия срабатывает, ёпта:
-
Когда ты тупо копируешь объект в лоб. Самый простой случай, тут даже думать не надо.
MyClass obj1; MyClass obj2(obj1); // Всё, просто скопировал. Прямой вызов. MyClass obj3 = obj1; // Тоже копирование, хоть и знак равенства. Это инициализация, а не присваивание! -
Когда суёшь объект в функцию по значению. Вот тут народ часто охуевает, откуда лишние вызовы берутся.
void foo(MyClass param); // Функция жрёт объект ПО ЗНАЧЕНИЮ MyClass obj; foo(obj); // Ёб твою мать! Сейчас `obj` скопируют в `param`. Вот тебе и вызов конструктора копирования. -
Когда функция возвращает объект по значению. Тут история пиздец интересная. Раньше (до C++17) это был геморрой и лишние копии. Сейчас компиляторы умные, часто вырезают лишнее (copy elision), а с C++17 это вообще гарантировано в таких случаях. Но принцип ты должен понимать.
MyClass createObject() { MyClass localObj; return localObj; // В теории — может копировать. На практике сейчас — обычно оптимизируют. } -
Когда копируешь член класса. Если в твоём классе есть другие объекты, их тоже надо скопировать правильно, а не просто хуй с горы бросить.
Смотри, живой пример, чтоб вообще всё стало ясно:
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource defaultn"; }
Resource(const Resource&) { std::cout << "Resource copyn"; } // Его конструктор копирования
};
class MyClass {
Resource res; // Член-объект
public:
MyClass() { std::cout << "MyClass defaultn"; }
// Вот наш герой! Копируем не только себя, но и член `res`!
MyClass(const MyClass& other) : res(other.res) {
std::cout << "MyClass copyn";
}
};
void byValue(MyClass c) { /* ... */ } // Функция-пожиратель копий
int main() {
std::cout << "--- Создаём оригинал ---n";
MyClass original; // Вызовы: Resource default, MyClass default
std::cout << "n--- Копируем инициализацией ---n";
MyClass copy = original; // БАМ! Resource copy, MyClass copy
std::cout << "n--- Передаём в функцию по значению ---n";
byValue(original); // И ещё раз! Resource copy, MyClass copy
return 0;
}
Важный момент на посошок: Современный C++ (C++11 и дальше) — он хитрая жопа. Он не любит лишнюю работу. Поэтому если объект можно не копировать, а переместить (как будто переставить кресло, а не делать новое), он так и сделает, через конструктор перемещения. Особенно когда функция возвращает временный объект. Но это уже другая история, про то, как избежать лишнего геморроя.