ПрограммированиеC++ разработчик

Что происходит при передаче объекта класса по значению в функцию и какие подводные камни стоит учитывать при реализации копирующего конструктора?

Проходите собеседования с ИИ помощником Hintsage

Ответ

При передаче объекта по значению в функцию в C++ происходит создание копии объекта с помощью конструктора копирования. Если в классе определён пользовательский конструктор копирования, то он вызывается для инициализации временного объекта-аргумента функции. Если не определён — используется компилятор по умолчанию, который выполняет побитовое копирование (shallow copy).

Подводные камни:

  • Если класс управляет ресурсами (например, имеет сырые указатели), по умолчанию сгенерированный конструктор копирования приведёт к ошибкам двойного освобождения памяти и утечкам.
  • Нужно убедиться, что конструктор копирования корректно копирует ресурсы (обычно deep copy).

Пример:

class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // Ошибка: shallow copy StringWrapper(const StringWrapper& other) : data(other.data) {} ~StringWrapper() { delete [] data; } }; void foo(StringWrapper s) { // ... } int main() { StringWrapper s1("hello"); foo(s1); // UB!!! return 0; }

Вопрос с подвохом

"Что будет, если определить конструктор копирования в классе с указателем так: MyClass(const MyClass &other) : data(other.data) {}? Какие последствия это вызывает?"

Верный ответ: Такой конструктор копирования создаст объект с указателем на ту же область памяти, что и у копируемого. При уничтожении двух объектов память будет освобождена дважды (double free), что приводит к неопределённому поведению. Следует реализовывать deep copy:

MyClass(const MyClass &other) { data = new int(*other.data); }

Примеры реальных ошибок из-за незнания тонкостей темы


История

В большом серверном проекте использовали контейнеры из объектов с "сырым" массивом внутри и стандартным копирующим конструктором (shallow copy). При передаче объектов по значению возникал double free и краши приложения, улавливаемые только в продакшне.


История

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


История

При возврате объекта по значению из функции в одной из внутренних систем хранения паролей данные очищались при уничтожении временного объекта (shallow copy), в результате чего реальный объект хранил обнулённый указатель, а утечка выявилась случайно в процессе аудита безопасности.