Последнее обновление:2026-10-12
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);
Этот код вызывает несколько вопросов:
- Почему счётчик умного указателя, сконструированного из nullptr-сырого-указателя, не равен 0?
- Безопасно ли делать delete nullptr?
1.Семантика пустого shared_ptr¶
Посмотрим прямо на исходный код shared_ptr; пустым считается:
- shared_ptr, сконструированный по умолчанию
- shared_ptr, сконструированный из nullptr_t
Только эти два случая считаются пустыми; shared_ptr же, сконструированный из сырого указателя, владеет этим указателем независимо от того, пуст он или нет.
Этим соответствуют три приведённых ниже конструктора.
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)
{}
Если в описанном выше случае сырой указатель равен nullptr, что произойдёт при выполнении delete nullptr? А при удалении дважды?
2.delete nullptr¶
Пусть есть следующий код — он упадёт после запуска? Или отработает нормально?
#include <iostream>
int main() {
int *p = nullptr;
delete p;
std::cout << "delete once" << std::endl;
delete p;
std::cout << "delete twice" << std::endl;
}
Ответ: нормальный вывод.
Конкретную причину смотрите в 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.
Если результатом вычисления выражения является нулевое значение указателя, деструкторы не вызываются, а функция освобождения памяти может как вызываться, так и не вызываться (это не специфицировано), однако стандартные функции освобождения гарантированно не делают ничего при передаче им нулевого указателя.
Совет по чтению
В этой статье обсуждается различие между инициализацией (initialization) и присваиванием (assignment) в C++; см. также список инициализации класса.
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- C++ битовые поля | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ константы const и его модификация | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事
- C++ restrict и оптимизации компилятора | C++那些事