目录
1.引入:为什么需要智能指针
2. 内存泄漏
2.1 什么是内存泄漏,内存泄漏的危害
2.2 内存泄漏分类(了解)
2.3 如何检测内存泄漏(了解)
2.4如何避免内存泄漏
3.智能指针的使用及原理
3.1 RAII
3.2 智能指针的原理
3.3 std::auto_ptr
3.4 std::unique_ptr
4.C++11和boost中智能指针的关系
本节主要介绍智能指针的相关用法。
#include
#include
#include
using namespace std;
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("zero was div");
return a / b;
}
void Func()
{
// 1、如果p1这里new 抛异常会如何?
// 2、如果p2这里new 抛异常会如何?
// 3、如果div调用这里又会抛异常会如何?
int *p1 = new int;
int *p2 = new int;
cout << div() << endl;
delete p1;
delete p2;
}
int main()
{
try
{
Func();
}
catch (const std::exception &e)
{
std::cerr << e.what() << '\n';
}
system("pause");
return 0;
}
#include
#include
#include
using namespace std;
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("zero was div");
return a / b;
}
void Func()
{
// 1、如果p1这里new 抛异常会如何?
// 2、如果p2这里new 抛异常会如何?
// 3、如果div调用这里又会抛异常会如何?
int *p1 = new int;
int *p2 = new int;
cout << div() << endl;
delete p1;
delete p2;
}
void MemoryLeaks(){
int *p1=(int*)malloc(sizeof(int));
int *p2=new int;
int *p3=new int[10];
//这里Func() 函数抛异常,导致delete []p3 没有执行
Func();
delete []p3;
}
int main()
{
// try
// {
// Func();
// }
// catch (const std::exception &e)
// {
// std::cerr << e.what() << '\n';
// }
try
{
MemoryLeaks();
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
system("pause");
return 0;
}
#include
#include
#include
using namespace std;
template
// 使用RAII思想设计的SmartPtr类
class smartPtr{
public:
smartPtr(T *ptr):_ptr(ptr){
cout<<"construct"<>a>>b;
if(b==0)
throw invalid_argument("zero was div");
return 0;
}
void Func(){
smartPtr sp1(new int);
smartPtr sp2(new int);
cout<
以下是结果,由此可见,即使抛了异常,类被销毁了也,内存也会释放。
3.2 智能指针的原理
上述的 SmartPtr 还不能将其称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可
以通过 -> 去访问所指空间中的内容,因此: AutoPtr 模板类中还得需要将 * 、 -> 重载下,才可让其
像指针一样去使用 。
#include
#include
#include
using namespace std;
template
// 使用RAII思想设计的SmartPtr类
class smartPtr
{
public:
smartPtr(T *ptr) : _ptr(ptr)
{
cout << "construct" << endl;
}
//解引用的重载
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
~smartPtr()
{
if (_ptr)
{
delete _ptr;
}
cout << "Destruction" << endl;
}
private:
T *_ptr;
};
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("zero was div");
return 0;
}
void Func()
{
smartPtr sp1(new int);
smartPtr sp2(new int);
cout << div() << endl;
}
class Date{
public:
int _year;
int _month;
int _day;
};
void test01(){
smartPtr sp1(new int);
*sp1=10;
cout<<*sp1< sp(new Date);
sp->_year=2018;
sp->_month=1;
sp->_day=1;
cout<_month<_year<_day<
总结一下智能指针的原理:
1. RAII 特性
2. 重载 operator* 和 opertaor-> ,具有像指针一样的行为。
3.3 std::auto_ptr
C++98 版本的库中就提供了 auto_ptr 的智能指针。下面演示的 auto_ptr 的使用及问题。 auto_ptr 的实现原理:管理权转移的思想,下面简化模拟实现了一份 bit::auto_ptr 来了解它的原 理
#include
#include
#include
using namespace std;
namespace myspace
{
template
class auto_ptr{
public:
auto_ptr(T *ptr):_ptr(ptr) {
}
auto_ptr(auto_ptr & sp):_ptr(sp._ptr){
//管理权转移
sp._ptr=nullptr;
}
auto_ptr operator=(auto_ptr &ap){
if(this!=&ap){
if(_ptr){
delete _ptr;
}
_ptr=ap._ptr;
ap._ptr=NULL;
}
return *this;
}
~auto_ptr(){
if(_ptr){
cout<<"delete:"<<_ptr<(){
return _ptr;
}
private:
T *_ptr;
};
} // namespace myspace
// 结论:auto_ptr是一个失败设计,很多公司明确要求不能使用auto_ptr
int main()
{
myspace::auto_ptr sp1(new int);
myspace::auto_ptr sp2(sp1);
*sp2=10;
cout<<*sp2<
#include
#include
#include
#include
using namespace std;
namespace myspace
{
template
class unique_ptr
{
public:
unique_ptr(T *ptr) : _ptr(ptr)
{
}
~unique_ptr()
{
if (_ptr)
{
cout << "delete _ptr" << _ptr << endl;
delete _ptr;
}
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
//将类中的默认的拷贝构造函数和赋值的重载方法进行了删除
unique_ptr(const unique_ptr &sp) = delete;
unique_ptr &operator=(const unique_ptr &sp) = delete;
private:
T *_ptr;
};
} // namespace myspace
void test01()
{
// myspace::unique_ptr sp(new int);
// myspace::unique_ptr sp2(sp); 报错
unique_ptr sp(new int);
// unique_ptr sp2(sp);
}
int main()
{
test01();
system("pause");
return 0;
}
#include
#include
#include
#include
using namespace std;
namespace myspace
{
template
class shared_ptr
{
public:
shared_ptr(T *ptr = nullptr) : _ptr(ptr), _pRefCount(new int(1)), _pmtx(new mutex)
{
}
shared_ptr(const shared_ptr &sp) : _ptr(sp._ptr), _pRefCount(sp._pRefCount), _pmtx(sp._pmtx)
{
Addref();
}
void Addref()
{
_pmtx->lock();
++(*_pRefCount);
_pmtx->unlock();
}
void Release()
{
_pmtx->lock();
bool flag = false;
if (--(*_pRefCount) == 0 && _ptr)
{
cout << "delete" << _ptr << endl;
delete _ptr;
delete _pRefCount;
flag = true;
}
_pmtx->unlock();
if (flag == true)
{
delete _pmtx;
}
}
shared_ptr &operator=(const shared_ptr &sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pmtx = sp._pmtx;
Addref();
}
return *this;
}
int use_count()
{
return *_pRefCount;
}
~shared_ptr()
{
Release();
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
T *get() const
{
return _ptr;
}
private:
T *_ptr;
int *_pRefCount;
mutex *_pmtx;
};
template
class weak_ptr
{
public:
weak_ptr() : _ptr(nullptr)
{
}
weak_ptr(const shared_ptr &sp) : _ptr(sp.get())
{
}
weak_ptr &operator=(const shared_ptr &sp)
{
_ptr = sp.get();
return *this;
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
private:
T *_ptr;
};
}
int main()
{
myspace::shared_ptr sp1(new int);
myspace::shared_ptr sp2(sp1);
myspace::shared_ptr sp3(sp1);
myspace::shared_ptr sp4(new int);
myspace::shared_ptr sp5(sp4);
sp1=sp2;
*sp2=3;
system("pause");
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
namespace myspace
{
template
class shared_ptr
{
public:
shared_ptr(T *ptr = nullptr) : _ptr(ptr), _pRefCount(new int(1)), _pmtx(new mutex)
{
}
shared_ptr(const shared_ptr &sp) : _ptr(sp._ptr), _pRefCount(sp._pRefCount), _pmtx(sp._pmtx)
{
Addref();
}
void Addref()
{
// _pmtx->lock();
++(*_pRefCount);
// _pmtx->unlock();
}
void Release()
{
_pmtx->lock();
bool flag = false;
if (--(*_pRefCount) == 0 && _ptr)
{
// cout << "delete" << _ptr << endl;
delete _ptr;
delete _pRefCount;
flag = true;
}
_pmtx->unlock();
if (flag == true)
{
delete _pmtx;
}
}
shared_ptr &operator=(const shared_ptr &sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pmtx = sp._pmtx;
Addref();
}
return *this;
}
int use_count()
{
return *_pRefCount;
}
~shared_ptr()
{
Release();
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
T *get() const
{
return _ptr;
}
private:
T *_ptr;
int *_pRefCount;
mutex *_pmtx;
};
template
class weak_ptr
{
public:
weak_ptr() : _ptr(nullptr)
{
}
weak_ptr(const shared_ptr &sp) : _ptr(sp.get())
{
}
weak_ptr &operator=(const shared_ptr &sp)
{
_ptr = sp.get();
return *this;
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
private:
T *_ptr;
};
}
struct Date
{
int _year = 0;
int _month = 0;
int _day = 0;
};
void SharePtrFunc(myspace::shared_ptr &sp, size_t n, mutex &mtx)
{
cout << sp.get() << endl;
for (size_t i = 0; i < n; ++i)
{
// 这里智能指针拷贝会++计数,智能指针析构会--计数,这里是线程安全的。
myspace::shared_ptr copy(sp);
// 这里智能指针访问管理的资源,不是线程安全的。所以我们看看这些值两个线程++了2n
// 次,但是最终看到的结果,并一定是加了2n
{
unique_lock lk(mtx);
copy->_year++;
copy->_month++;
copy->_day++;
}
}
}
void test02(){
myspace::shared_ptr p(new Date);
cout<_year<_month<_day< sp1(new int);
// myspace::shared_ptr sp2(sp1);
// myspace::shared_ptr sp3(sp1);
// myspace::shared_ptr sp4(new int);
// myspace::shared_ptr sp5(sp4);
// sp1 = sp2;
// *sp2 = 3;
system("pause");
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
namespace myspace
{
template
class shared_ptr
{
public:
shared_ptr(T *ptr = nullptr) : _ptr(ptr), _pRefCount(new int(1)), _pmtx(new mutex)
{
}
shared_ptr(const shared_ptr &sp) : _ptr(sp._ptr), _pRefCount(sp._pRefCount), _pmtx(sp._pmtx)
{
Addref();
}
void Addref()
{
_pmtx->lock();
++(*_pRefCount);
_pmtx->unlock();
}
void Release()
{
_pmtx->lock();
bool flag = false;
if (--(*_pRefCount) == 0 && _ptr)
{
// cout << "delete" << _ptr << endl;
delete _ptr;
delete _pRefCount;
flag = true;
}
_pmtx->unlock();
if (flag == true)
{
delete _pmtx;
}
}
shared_ptr &operator=(const shared_ptr &sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pmtx = sp._pmtx;
Addref();
}
return *this;
}
int use_count()
{
return *_pRefCount;
}
~shared_ptr()
{
Release();
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
T *get() const
{
return _ptr;
}
private:
T *_ptr;
int *_pRefCount;
mutex *_pmtx;
};
template
class weak_ptr
{
public:
weak_ptr() : _ptr(nullptr)
{
}
weak_ptr(const shared_ptr &sp) : _ptr(sp.get())
{
}
weak_ptr &operator=(const shared_ptr &sp)
{
_ptr = sp.get();
return *this;
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
private:
T *_ptr;
};
}
struct Date
{
int _year = 0;
int _month = 0;
int _day = 0;
};
void SharePtrFunc(myspace::shared_ptr &sp, size_t n, mutex &mtx)
{
cout << sp.get() << endl;
for (size_t i = 0; i < n; ++i)
{
// 这里智能指针拷贝会++计数,智能指针析构会--计数,这里是线程安全的。
myspace::shared_ptr copy(sp);
// 这里智能指针访问管理的资源,不是线程安全的。所以我们看看这些值两个线程++了2n
// 次,但是最终看到的结果,并一定是加了2n
{
unique_lock lk(mtx);
copy->_year++;
copy->_month++;
copy->_day++;
}
}
}
void test02(){
myspace::shared_ptr p(new Date);
cout<_year<_month<_day< _next;
shared_ptr _prev;
~ListNode(){
cout<<"~ListNode()"< node1(new ListNode);
std:: shared_ptr node2(new ListNode);
cout<_next=node2;
node2->_prev=node1;
cout< sp1(new int);
// myspace::shared_ptr sp2(sp1);
// myspace::shared_ptr sp3(sp1);
// myspace::shared_ptr sp4(new int);
// myspace::shared_ptr sp5(sp4);
// sp1 = sp2;
// *sp2 = 3;
system("pause");
return 0;
}
#include
#include
#include
using namespace std;
#include
#include
struct ListNode
{
int _data;
weak_ptr _next;
weak_ptr _prev;
~ListNode(){
cout<<"~ListNode()"< node1(new ListNode);
shared_ptr node2(new ListNode);
cout<_next=node2;
node2->_prev=node1;
cout<
#include
#include
#include
using namespace std;
#include
#include
struct ListNode
{
int _data;
weak_ptr _next;
weak_ptr _prev;
~ListNode(){
cout<<"~ListNode()"< node1(new ListNode);
shared_ptr node2(new ListNode);
cout<_next=node2;
node2->_prev=node1;
cout<
struct FreeFunc
{
void operator()(T* ptr){
cout<<"free:"<
struct DeleteArrayFunc{
void operator()(T *ptr){
cout<<"delete[]"< freeFunc;
shared_ptr sp1((int *)malloc(4),freeFunc);
DeleteArrayFunc deleteArrayFunc;
shared_ptr sp2( (int *)malloc(4),deleteArrayFunc);
shared_ptr sp4(new A[10],[](A *p){delete[]p;});
shared_ptr sp5(fopen("test.txt","w"),[](FILE *p){
fclose(p);
});
}
int main()
{
// test01();
test02();
system("pause");
return 0;
}