C++ delete ptr 和 ptr = nullptr 的区别
delete ptr
delete ptr
是释放 ptr
所指向的对象资源,而 ptr
依然存在,且依然指向那片内存地址。
ptr = nullptr
ptr = nullptr
是将 ptr
指向空指针,和其所指向的对象没关系。
试着实现一个 unique_ptr
template <typename T>
class UniquePtr {
private:
T *_ptr;
public:
// 默认构造
UniquePtr() : _ptr(nullptr) { }
explicit UniquePtr(T *ptr) : _ptr(ptr) { }
~UniquePtr() {
delete _ptr;
// 无需置 nullptr,因为析构函数会被调用,_ptr 会被销毁
// 置空无意义
}
// 拷贝构造 删除
UniquePtr(const UniquePtr &) = delete;
UniquePtr &operator=(const UniquePtr &) = delete;
// 移动构造
UniquePtr(UniquePtr &&p) noexcept : _ptr(p._ptr) {
// 至于这里为什么不需要 delete _ptr
// 是因为这是移动构造函数,是个构造函数!_ptr 本来就没有资源
p._ptr = nullptr;
}
UniquePtr &operator=(UniquePtr &&p) noexcept {
if (p != *this) {
delete _ptr; // 第一步,释放当前资源
_ptr = p._ptr; // 第二步,将当前指针指向新的资源
p._ptr = nullptr; // 第三步,将原来的指针置空
}
return *this;
}
T *get() const { // 返回指针
return _ptr;
}
T *operator->() const { // 返回指针
return _ptr;
}
T &operator*() const { // 解引用
return *_ptr;
}
T *release() {
// 这里不能 delete _ptr
// 因为 release 只是解除 UniquePtr 对资源的所有权,但资源还是存在的
T *tmp = _ptr;
_ptr = nullptr;
return tmp;
}
void reset(T *newptr = nullptr) {
if (_ptr != newptr) {
delete _ptr; // 释放当前资源
_ptr = newptr; // 指向新资源
// 这里不需要置空 newptr
// 是否置空 new ptr 由用户决定
}
}
};
UniquePtr &operator=(UniquePtr &&p)
移动赋值运算符的原理如下图: