Última actualización:2026-10-12
Inicialización y asignación en C++¶
C++ iv¶
int* p = nullptr;
std::shared_ptr<int> s(p); // 计数器1
std::shared_ptr<int> s2(s); // 计数器2
assert(s.use_count() == 2);
- ¿Por qué el contador del puntero inteligente construido a partir de un puntero en bruto nullptr no vale 0?
- ¿Es seguro hacer delete nullptr?
1. Semántica del shared_ptr vacío¶
Si miramos directamente el código fuente de shared_ptr, lo que se considera vacío significa:
- Construir un shared_ptr con el constructor por defecto
- Construir un shared_ptr a partir de nullptr_t
Solo estos dos casos se consideran vacíos; en cambio, un shared_ptr construido a partir de un puntero en bruto toma la posesión de ese puntero, sea o no nulo.
Corresponden respectivamente a los tres constructores siguientes.
private:
element_type* __ptr_;
__shared_weak_count* __cntrl_;
public:
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR shared_ptr() _NOEXCEPT
: __ptr_(nullptr),
__cntrl_(nullptr)
{ }
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR shared_ptr(nullptr_t) _NOEXCEPT
: __ptr_(nullptr),
__cntrl_(nullptr)
{ }
shared_ptr(_Yp* __p, _Dp __d)
: __ptr_(__p)
{}
2. delete nullptr¶
Supongamos el siguiente código: ¿al ejecutarlo se bloqueará? ¿O funcionará con normalidad?
#include <iostream>
int main() {
int *p = nullptr;
delete p;
std::cout << "delete once" << std::endl;
delete p;
std::cout << "delete twice" << std::endl;
}
La razón concreta, según cppreference:
If expression evaluates to a null pointer value, no destructors are called, and the deallocation function may or may not be called (it's unspecified), but the default deallocation functions are guaranteed to do nothing when passed a null pointer.
Si la expresión se evalúa como un valor de puntero nulo, no se llama a ningún destructor, y la función de desasignación puede llamarse o no (no está especificado), pero las funciones de desasignación por defecto garantizan no hacer nada cuando se les pasa un puntero nulo.
Consejo de lectura
Este artículo trata de la diferencia en C++ entre inicialización (initialization) y asignación (assignment); puede consultarse también la lista de inicialización de clases.
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++那些事
- Formas de devolver varios valores en C++ | C++那些事
- La palabra clave mutable en C++ | C++那些事
- C++ restrict y optimización del compilador | C++那些事