一、普通指针
int main()
{
int *p = new int(10);
// if(true) return 0; 会导致delete运行不到
*p = 30;
delete p;
return 0;
}
裸指针存在的问题:
- 需要自己手动释放,如果不释放,就导致堆内存丢失,从而导致内存泄露;
- delete之前存在语句提前return,导致delete运行不到,从而导致内存泄露。
二、RAII思想(资源获取就是初始化)
- RAII是一种资源管理、避免泄露的惯用法,对资源进行类封装管理;
- RAII的做法是使用一个对象,再对象构造的时候获取对应的资源,在对象生命周期内控制对资源的访问,析构对象的时候,释放构造时获取的资源;
- 资源一般指的是 内存、文件句柄、套接字和互斥锁等系统资源。
三、实现一个简单的智能指针(对普通指针进行封装)
为了避免忘记释放内存导致的内存泄露,设计的一种自动管理堆内存的方法;
思想: 保证做到资源的自动释放,利用栈的对象出作用域能自动析构,来做到资源的释放!
#include<iostream>
#include<memory>
using namespace std;
/*
实现简单的解引用*重载和访问->重载
*/
template<typename T>
class Ptr
{
public:
Ptr(T* ptr = nullptr) :_ptr(ptr) { cout << "Ptr构造" << endl; }
~Ptr()
{
cout << "~Ptr析构" << endl;
if (_ptr != nullptr)
{
delete _ptr;
_ptr = nullptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
class Test
{
public:
Test() {}
~Test() {}
void test() { cout << "Test::test()" << endl; }
private:
};
int main()
{
{
Ptr<int> p(new int);
*p = 20;
cout << *p << endl;
} // 出作用域析构
Ptr<Test> p2(new Test());
p2->test(); // 具体实现(ptr2.operator->())->test();
return 0;
}
// 运行结果
Ptr构造
20
~Ptr析构
Ptr构造
Test::test()
~Ptr析构
四、注意事项
关于智能指针能不能定义在堆上:
Ptr<int>* ptr1 = new Ptr<int>(new int);
- 如果定义在堆上的话,ptr1依旧是一个裸指针,是一个指向**Ptr<int>**对象的指针,最后还是需要
delete ptr1;释放资源。
- 智能指针是希望通过一个类对象管理底层指针指向的内存资源,而不是通过一个指向改对象的指针来管理。