Последнее обновление:2026-10-12
C++ умные указатели как параметры функций¶
C++那些事: когда умный указатель использовать как параметр функции¶
Обычно можно видеть, что одни функции используют в качестве параметра умный указатель, а другие — голый указатель; что же выбрать? Каковы принципы использования?
В этом разделе объяснение строится на советах (tips) из abseil.
Посмотрите на код ниже — что с ним не так?
bool CanYouPetTheDog(const std::shared_ptr<Dog>& dog,
absl::Duration min_delay) {
return dog->GetLastPetTime() + min_delay < absl::Now();
}
Функция CanYouPetTheDog никак не влияет на владение параметром dog, но её сигнатура требует, чтобы он хранился в std::shared_ptr. Это создаёт ненужную зависимость от конкретной модели владения, хотя самой функции такая зависимость не нужна. Эта зависимость мешает вызывающему коду использовать другие модели — например, std::unique_ptr или объекты, сконструированные на стеке.
Использование указателей/ссылок¶
Когда владение не затрагивается, используйте ссылку или указатель. Применяя ссылку/указатель, мы устраняем зависимость от конкретной модели владения и позволяем нашей функции работать с любым объектом типа Dog.
bool CanYouPetTheDog(const Dog& dog, absl::Duration min_delay) {
return dog.GetLastPetTime() + min_delay < absl::Now();
}
С таким определением функцию можно вызывать независимо от того, какая модель владения у вызывающего:
Dog stack_dog;
if (CanYouPetTheDog(stack_dog, delay)) { ... }
auto heap_dog = std::make_unique<Dog>();
if (CanYouPetTheDog(*heap_dog, delay)) { ... }
CustomPetPtr<Dog> custom_dog = CreateDog();
if (CanYouPetTheDog(*custom_dog, delay)) { ... }
Если функция изменяет переданное значение, передавайте изменяемую ссылку или сырой указатель — способ применения тот же, что описан выше.
Использование умных указателей¶
Используйте умные указатели, когда функция изменяет владение; приведённый ниже код даёт несколько перегрузок для разных параметров-умных указателей. Первая перегрузка предполагает принятие владения переданным объектом, вторая добавляет к переданному объекту разделяемую ссылку. Выбор между этими двумя операциями зависит от того, как вызывающая сторона распорядится владением Dog. Невозможно принять владение Dog, расположенным на стеке, поскольку забрать владение со стека нельзя.
class Human {
public:
...
void Adopt(std::unique_ptr<Dog> dog) {
pets_.push_back(std::move(dog));
}
void Adopt(std::shared_ptr<Cat> cat) {
pets_.push_back(std::move(cat));
}
private:
std::vector<std::shared_ptr<Pet>> pets_;
...
};
Резюме¶
Если владение не передаётся и не изменяется, следует избегать использования умного указателя в качестве параметра функции.
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- C++ битовые поля | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ константы const и его модификация | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ инициализация и присваивание | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事