Última actualización:2026-10-12
Punteros inteligentes como parámetros de función en C++¶
C++那些事: cuándo usar punteros inteligentes como parámetros de función¶
Normalmente vemos que algunas funciones usan punteros inteligentes como parámetros y otras usan punteros crudos; ¿cuál usar? ¿Cuál es el principio a seguir?
Esta sección usa los tips de abseil para explicarlo.
¿Qué problema tiene el siguiente código?
bool CanYouPetTheDog(const std::shared_ptr<Dog>& dog,
absl::Duration min_delay) {
return dog->GetLastPetTime() + min_delay < absl::Now();
}
La función CanYouPetTheDog no afecta a la propiedad (ownership) de su parámetro dog, pero su firma exige almacenarlo en un std::shared_ptr. Esto crea una dependencia innecesaria de un modelo de propiedad concreto, aunque la función en sí no la necesite. Esa dependencia impide que quienes llaman usen otros modelos, como std::unique_ptr o construir el objeto en la pila.
Usar puntero/referencia¶
Cuando la propiedad no se ve afectada, use referencia o puntero. Al usar referencia/puntero eliminamos la dependencia de un modelo de propiedad concreto y permitimos que nuestra función trabaje con cualquier objeto de tipo Dog.
bool CanYouPetTheDog(const Dog& dog, absl::Duration min_delay) {
return dog.GetLastPetTime() + min_delay < absl::Now();
}
Con la definición anterior, la función puede llamarse independientemente del modelo de propiedad de quien llama:
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)) { ... }
Si la función modifica el valor pasado, pase una referencia mutable o un puntero crudo, con el mismo uso que el anterior.
Usar punteros inteligentes¶
Use punteros inteligentes cuando la función modifica la propiedad; el siguiente código ofrece varias sobrecargas para distintos parámetros de puntero inteligente. La primera sobrecarga asume la toma de posesión del objeto pasado; la segunda añade una referencia compartida al objeto pasado. Ambas operaciones dependen de cómo la parte llamante gestione la propiedad del Dog. No se puede tomar posesión de un Dog ubicado en la pila, porque su propiedad no puede retirarse de la pila.
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_;
...
};
Resumen¶
Si la propiedad no se transfiere ni se modifica, conviene evitar los punteros inteligentes como parámetros de función.
Temas relacionados¶
- Funciones virtuales puras y clases abstractas en C++ | C++那些事
- Aserciones assert en C++ | C++那些事
- Campos de bits en C++ | C++那些事
- Implementar el polimorfismo de C++ en lenguaje C | C++那些事
- const en C++: constantes y modificación | C++那些事
- La familia completa de const en C++ | C++那些事
- El operador de desreferencia * en C++ | C++那些事
- Inicialización y asignación en C++ | C++那些事
- Formas de devolver varios valores en C++ | C++那些事
- La palabra clave mutable en C++ | C++那些事