Как передать параметр в функцию в C++

«Как передать параметр в функцию в C++» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

1. Передача по значению (copy): Создается локальная копия. Изменения внутри функции не затрагивают оригинал. Подходит для примитивных типов и небольших, дешевых для копирования объектов.

void modifyCopy(int x) {
    x = 42; // Меняется только локальная копия
}

2. Передача по указателю (pointer): Передается адрес объекта. Позволяет изменять оригинал и передавать nullptr. Требует явного разыменования (*) и проверки на nullptr.

void modifyViaPointer(int* ptr) {
    if (ptr) { // Всегда проверяем!
        *ptr = 42; // Меняем значение по адресу
    }
}

3. Передача по ссылке (reference): Альтернатива указателю без синтаксиса разыменования. Ссылка не может быть nullptr (если только это не ссылка в состоянии "dangling"). Изменяет оригинал.

void modifyViaReference(int& ref) {
    ref = 42; // Меняем оригинальную переменную
}

4. Передача по константной ссылке (const T&): Оптимальный способ для передачи больших объектов (строк, векторов, пользовательских классов), которые не нужно изменять. Избегает дорогого копирования и гарантирует, что функция не изменит объект.

void printLargeObject(const std::vector<std::string>& data) {
    for (const auto& item : data) {
        std::cout << item << 'n';
    }
    // data.push_back("new"); // Ошибка компиляции: data константная
}

5. Передача по rvalue-ссылке (T&&): Для поддержки семантики перемещения, когда объект больше не нужен вызывающему коду (например, временный объект). Позволяет эффективно "забрать" ресурсы.

void takeOwnership(std::unique_ptr<int>&& ptr) {
    // Теперь ptr принадлежит этой функции
}
// Вызов: takeOwnership(std::make_unique<int>(5));

Практическое правило:

  • Входные параметры, которые не меняются и дороги для копирования — const T&.
  • Выходные или входно-выходные параметры — T& (если объект гарантированно существует) или *`T** (если нужна возможность передатьnullptr`).
  • Примитивные типы (int, bool) — по значению.
  • Чтобы принять владение ресурсом — T&& (для move-семантики).