Última atualização:2026-10-12
Inicialização e atribuição em 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);
Este código levanta algumas perguntas:
- Por que o contador do ponteiro inteligente construído a partir do ponteiro bruto nullptr não é 0?
- delete nullptr é seguro?
1.Semântica de um shared_ptr vazio¶
Vejamos diretamente o código-fonte do shared_ptr: o chamado vazio refere-se a:
- construir um shared_ptr por padrão
- construir um shared_ptr a partir de um nullptr_t
Somente nesses dois casos ele é vazio; já um shared_ptr construído a partir de um ponteiro bruto é dono da propriedade desse ponteiro, esteja ele vazio ou não.
Correspondem, respectivamente, aos três construtores a seguir.
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)
{}
No caso acima, em que o ponteiro bruto é nullptr, o que acontece ao executar delete nullptr? E o que aconteceria se fosse excluído duas vezes?
2.delete nullptr¶
Suponha o código abaixo: após a execução, ele falhará (crash) ou rodará normalmente?
#include <iostream>
int main() {
int *p = nullptr;
delete p;
std::cout << "delete once" << std::endl;
delete p;
std::cout << "delete twice" << std::endl;
}
A resposta é: a saída é normal.
O motivo específico está no 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.
Se a expressão avaliar para um valor de ponteiro nulo, nenhum destrutor é chamado, e a função de desalocação pode ou não ser chamada (é um comportamento não especificado), mas as funções de desalocação padrão garantidamente não fazem nada quando recebem um ponteiro nulo.
Dica de leitura
Este artigo discute a diferença entre inicialização (initialization) e atribuição (assignment) em C++; veja também Lista de inicialização de classes.
Tópicos relacionados¶
- Funções virtuais puras e classes abstratas em C++ | C++那些事
- Asserções com assert em C++ | C++那些事
- Bit fields em C++ | C++那些事
- Implementando polimorfismo de C++ em linguagem C | C++那些事
- Constantes e modificadores com const em C++ | C++那些事
- A família completa do const em C++ | C++那些事
- O operador de desreferência * em C++ | C++那些事
- Formas de retornar múltiplos valores em C++ | C++那些事
- A palavra-chave mutable em C++ | C++那些事
- C++ restrict e otimização do compilador | C++那些事