Почему при вызове return вызывается конструктор копирования, а не перегрузка оператора =?

При вызове return в C++, компилятор обычно использует конструктор копирования для создания временной копии объекта, которая будет возвращена из функции. Это происходит потому, что в момент вызова return, исполняющаяся функция завершается, и все локальные переменные, включая возвращаемое значение, становятся недействительными.

Перегрузка оператора присваивания (=) используется для присваивания значения одного объекта другому уже существующему объекту. Она не предназначена для создания новых объектов.

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

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

Если вы хотите избежать вызова конструктора копирования при возврате объекта из функции, можно использовать перемещающий конструктор (move constructor) или перемещающий оператор присваивания (move assignment operator) вместо конструктора копирования. Это особенно полезно, если у вас есть объёмные данные, которые можно перемещать, не создавая копий и не потребляя дополнительной памяти.

В C++11 и более поздних стандартах, можно также использовать семантику перемещения (move semantics) для обеспечения более эффективного и быстрого перемещения объектов. Это позволяет передавать и возвращать объекты через rvalue-ссылки, что позволяет избегать необходимости создавать копии объектов при возврате из функции.