智能指针
- 使用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;
}