对于c++这种没有垃圾回收机制的语言来说,主要关注两种类型的内存泄漏;
(1) 堆内存泄漏:比如使用new、malloc等从堆中分配的资源,没有用delete和free删掉
(2) 系统资源泄漏:系统分配的资源如socket等没有被释放掉。
智能指针是一个类, 这个类的构造函数会传入一个普通指针,析构函数中释放传入的指针。智能指针都是栈上的对象,所以当函数(或程序)结束时会自动会被释放。
引用型智能指针的实现:
template<typename T>
class SmartPointer
{
public:
//构造函数
SmartPointer(T* p = 0) : ptr(p), reference_count(new size_t)
{
if (p)
{
*reference_count = 1;
}
else
{
*reference_count = 0;
}
}
//拷贝构造函数
SmartPointer(const SmartPointer& other)
{
if (this != other)
{
ptr = other.ptr;
reference_count = other.reference_count;
reference_count++;
}
}
//operator= 重载
SmartPointer& operator=(const SmartPointer& other)
{
if (ptr == other.ptr)
return *this;
releaseCount();
ptr = other.ptr;
reference_count = other.reference_count;
(*reference_count)++;
return *this;
}
//重载操作符
T& operator*()
{
if (ptr)
return *ptr;
}
T* operator->()
{
if (ptr)
return ptr;
}
~SmartPointer()
{
if (--(*reference_count) == 0)
{
delete ptr;
delete reference_count;
}
}
private:
size_t *reference_count;
T *ptr;
void releaseCount()
{
if (ptr)
{
(*reference_count)--;
if (*reference_count == 0)
{
delete reference_count;
delete ptr;
}
}
}
};
shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0的时候,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。
注意事项:不要用一个原始指针初始化多个shared_ptr; 不要在函数实参中创建shared_ptr,在调用函数之前先定义以及初始化它; 不要讲this指针作为shared_ptr返回出来; 要避免循环引用。
unique_ptr是独占的智能指针
unique_ptr是一个独占的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另外一个unique_ptr. unique_ptr不允许赋值,但是可以通过函数返回给其他的unique_ptr,还可以通过std::move来转移到其它的unique_ptr, 这样它本身就不再拥有原来的指针的所有权了。如果希望只有一个只能指针管理或管理数组就用unique_ptr,如果希望多个智能指针管理同一个资源就用shared_ptr。
weak_ptr弱引用的智能指针:
弱引用的智能指针weak_ptr是用来监视shared_ptr的,不会使引用计数加1,它不管理shared_ptr内部的指针,主要是为了监视shared_ptr的生命周期。weak_ptr没有重载运算符*和->, 因此它不会共享指针,不能操作资源,主要是为了通过shared_ptr获得资源的监测权,它的构造不会增加引用计数,它的析构不会减少引用计数。weak_ptr还可以用来返回this指针和解决循环引用的问题。
循环计数问题:
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
public:
shared_ptr<B> pb;
~A() { cout << "destruct A" << endl; }
A() { cout << "constrct A" << endl; }
};
class B
{
public:
shared_ptr<A> pa;
~B() { cout << "destruct B" << endl; }
B() { cout << "construct B" << endl; }
};
int main()
{
shared_ptr<A> spa = make_shared<A>();
shared_ptr<B> spb = make_shared<B>();
spa->pb = spb;
spb->pa = spa;
cout << "spa use_count" << spa.use_count() << " spb use_count"
<< spb.use_count() << endl;
return 0;
}
解决办法:
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
public:
weak_ptr<B> pb;
~A() { cout << "destruct A" << endl; }
A() { cout << "constrct A" << endl; }
};
class B
{
public:
weak_ptr<A> pa;
~B() { cout << "destruct B" << endl; }
B() { cout << "construct B" << endl; }
};
int main()
{
shared_ptr<A> spa = make_shared<A>();
shared_ptr<B> spb = make_shared<B>();
spa->pb = spb;
spb->pa = spa;
cout << "spa use_count" << spa.use_count() << " spb use_count"
<< spb.use_count() << endl;
return 0;
}