【C++】智能指针

发布于:2025-03-26 ⋅ 阅读:(25) ⋅ 点赞:(0)

智能指针

  • 使用new在堆区动态分配内存时,需要delete释放否则会导致内存泄漏,所以采用智能指针即将动态创建时的指针传入,然后通过智能指针的析构函数delete即可释放资源,通过RAII技术确保内存被正确释放,有效防止内存泄漏。
  • 智能指针实际上是类对象,重载了类如->、*等指针常用的运算符,只是表现形式像指针
  • C++11摒弃auto_ptr并新增提供了三种智能指针unique_ptr、shared_ptr、weak_ptr, 其作用和使用详见 C++11新特性 第4点
  • 示例-手动实现简单的智能指针类来管理动态创建的对象
#include<iostream>
#include<string>
using namespace std;

//类模板-智能指针类
template<typename CLASSNAME>
class SmartPoint {
public:
	SmartPoint() {
		this->m_ptr = nullptr;
	}
	SmartPoint(CLASSNAME *ptr) {
		this->m_ptr = ptr;
	}
    // 禁止拷贝构造和拷贝赋值
    SmartPoint(const SmartPoint&) = delete;
    SmartPoint& operator=(const SmartPoint&) = delete;
    //RAII机制释放资源
	~SmartPoint() {
		if (this->m_ptr != nullptr) {
			cout<<"use ~SmartPoint()"<<endl;
			delete this->m_ptr;
			this->m_ptr = nullptr;
		}
	}
	// 移动构造函数
	SmartPoint(SmartPoint&& other) noexcept : m_ptr(other.m_ptr) {//初始化列表不允许用this,直接使用成员变量即可
	    other.m_ptr = nullptr;  // 确保原对象不再拥有资源
	}
	
	// 移动赋值运算符
	SmartPoint& operator=(SmartPoint&& other) noexcept {
	    if (this != &other) {
	        delete this->m_ptr;       // 释放当前资源
	        this->m_ptr = other.m_ptr;
	        other.m_ptr = nullptr;
	    }
	    return *this;
	}
	explicit operator bool() const { 
	    return this->m_ptr != nullptr; 
	}
	CLASSNAME* operator->() const{//重载->
	if (!this->m_ptr) {
	        throw std::runtime_error("Attempt to dereference null pointer");
	    }
		return this->m_ptr;
	}
    CLASSNAME& operator*() const{//重载*
    if (!this->m_ptr) {
		    throw std::runtime_error("Attempt to dereference null pointer");
		}
        return *(this->m_ptr);
    }

    CLASSNAME* get() const { return this->m_ptr; } 
    
    CLASSNAME* release() noexcept{ 
        CLASSNAME* ptr = this->m_ptr;
        this->m_ptr = nullptr;
        return ptr;
    }
    const CLASSNAME* release() const noexcept = delete;  // 禁止const对象release
    
    void set(CLASSNAME* ptr) {
        if (this->m_ptr != ptr) {
            CLASSNAME* old = this->m_ptr;
			this->m_ptr = ptr;  // 先设置新指针
			delete old;         // 再删除旧指针
        }
    }
    
private:
    CLASSNAME* m_ptr;//内部维护指针
};

//父类
template<typename NAMETYPE,typename AGETYPE>
class Person {
public:
	Person(NAMETYPE name, AGETYPE age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	virtual ~Person() = default;//确保子类资源释放
	virtual void show() {
		cout << this->m_Age<<"--" << this->m_Name << endl;
	}
	NAMETYPE m_Name;
	AGETYPE m_Age;
};

//子类
template<typename NAMETYPE, typename AGETYPE>
class Son :public Person<NAMETYPE, AGETYPE> {
public:
	Son(NAMETYPE name, AGETYPE age) :Person<NAMETYPE,AGETYPE>(name, age) {//调用父类有参构造
	}
	~Son(){
		cout<<"use 	~Son()"<<endl;
	}
	void show() override {//确保重写
		cout << this->m_Name<<"--" << this->m_Age << endl;
	}
};

int main() {
	
	//通过有参构造使用
	Person<string,int>* p1 = new Person<string, int>("Tom", 22);
	SmartPoint<Person<string,int>> sp1(p1);
	sp1->show();

	Person<string, int>* p2 = new Son<string, int>("JERRY", 22);
	SmartPoint<Person<string, int>> sp2(p2);
	sp2->show();
	
	//调用get、set使用
	SmartPoint<Person<string, int>> sp3;
	Person<string, int>* p3 = new Son<string, int>("Tom-Mom", 44);
	sp3.set(p3);
	sp3.get()->show();
	
	//测试release
	auto rawPtr = sp3.release();//模仿移动语义
	rawPtr->show();
	delete rawPtr;
	
	
	 // 测试移动语义-RAII机制仅释放两次
	SmartPoint<Person<string, int>> sp4 = std::move(sp1);
	if (!sp1) cout << "sp1 is empty after move"<<endl;
	sp4->show();
	

	return 0;
}