(未完)【C/C++】C++智能指针

来源:互联网 发布:千里眼ip扫描软件 编辑:程序博客网 时间:2024/06/05 15:24

我们知道堆上申请的空间必须通过手动释放来回收,如果忘记这一点,很容易造成内存泄漏。智能指针的引入就是为了解决如何在正确的时机(已经没有利用价值)释放堆上申请的空间,其实现原理是通过在指针外面包一层类,并在栈上生成此类的对象,当它在栈上被自动回收的时候,将堆上的空间也释放掉。

1. 重新造一个轮子

自定义智能指针遵循以下两个原则:
1). 智能指针类必须定义为类模板,这样才能hold住所有具体类
2). 引用计数必须包含在具体类中,即只在最源头保存一个引用计数

ReferenceCounted.h

所有具体类必须继承自ReferenceCounted类。其内部包含引用计数,当被一个SmartPtr引用时就自增,当一个SmartPtr被回收时就自减。当引用计数减为0时,通过调用delete this显式地将自己回收。
#ifndef REFERENCECOUNTED_H#define REFERENCECOUNTED_Hclass ReferenceCounted{public:ReferenceCounted(){referenceCounter = 0;}void AddRef(){++referenceCounter;}void Release(){if (referenceCounter > 0 && --referenceCounter == 0){delete this;}}protected:// 虚析构函数!virtual ~ReferenceCounted(){}private:// 引用计数int referenceCounter;};#endif

SmartPtr.h

SmartPtr类被定义为类模板,可以接收任何继承自ReferenceCounted类的具体类。
#ifndef SMARTPTR_H#define SMARTPTR_H// ReferenceCountedT必须是一个继承自ReferenceCounted的类template <class ReferenceCountedT>class SmartPtr{public:// 构造函数一:传入类型为ReferenceCountedT的指针来构造SmartPtr,必须保证p所指向的内容在堆上SmartPtr(ReferenceCountedT *p);// 构造函数二:拷贝构造函数,用一个SmartPtr来构造另一个SmartPtrSmartPtr(const SmartPtr<ReferenceCountedT> &p);~SmartPtr();// 重载赋值运算符一:必须保证p所指向的内容在堆上SmartPtr& operator =(const ReferenceCountedT *p);// 重载赋值运算符二:智能指针间赋值SmartPtr& operator =(const SmartPtr<ReferenceCountedT> &p);// 重载取值运算符ReferenceCountedT& operator *() const;// 重载成员选择运算符ReferenceCountedT* operator ->() const;// 重置SmartPtr的内部指针void Reset(ReferenceCountedT *p = NULL);// 获得内部指针ReferenceCountedT* Get();private:void Dispose();ReferenceCountedT *ptr;};// 用法// ReferenceCounted *p = new ReferenceCounted();// SmartPtr<ReferenceCounted> sp(p);template <class ReferenceCountedT>SmartPtr<ReferenceCountedT>::SmartPtr(ReferenceCountedT *p){ptr = p;if (ptr){ptr->AddRef();}}// 用法// ReferenceCounted *p = new ReferenceCounted();// SmartPtr<ReferenceCounted> sp1(p);// SmartPtr<ReferenceCounted> sp2(sp1);template <class ReferenceCountedT>SmartPtr<ReferenceCountedT>::SmartPtr(const SmartPtr<ReferenceCountedT> &p){ptr = p.ptr;if (ptr){ptr->AddRef();}}template <class ReferenceCountedT>SmartPtr<ReferenceCountedT>::~SmartPtr(){Dispose();}template <class ReferenceCountedT>SmartPtr<ReferenceCountedT>& SmartPtr<ReferenceCountedT>::operator =(const ReferenceCountedT *p){Reset(p);return *this;}template <class ReferenceCountedT>SmartPtr<ReferenceCountedT>& SmartPtr<ReferenceCountedT>::operator =(const SmartPtr<ReferenceCountedT> &p){Reset(p.ptr);return *this;}template <class ReferenceCountedT>ReferenceCountedT& SmartPtr<ReferenceCountedT>::operator *() const{return *ptr;}template <class ReferenceCountedT>ReferenceCountedT* SmartPtr<ReferenceCountedT>::operator ->() const{return ptr;}template <class ReferenceCountedT>void SmartPtr<ReferenceCountedT>::Reset(ReferenceCountedT *p){// 避免自赋值self-assignmentif (ptr != p){Dispose();ptr = p;if (ptr){ptr->AddRef();}}}template <class ReferenceCountedT>ReferenceCountedT* SmartPtr<ReferenceCountedT>::Get(){return ptr;}template <class ReferenceCountedT>void SmartPtr<ReferenceCountedT>::Dispose(){if (ptr){ptr->Release();}}#endif
测试代码:

MyClass.h

MyClass类表示一个具体类,继承自ReferenceCounted。
#include "ReferenceCounted.h"class MyClass : public ReferenceCounted{public:MyClass(){num = 0;}int MyFoo(){++num;return num;}int num;protected:~MyClass(){}};

Main.cpp

#include "SmartPtr.h"#include "MyClass.h"#include <crtdbg.h>#include <vector>#include <iostream>using namespace std;void main(void){{MyClass *rc1 = new MyClass();SmartPtr<MyClass> sp1 = rc1; // 普通构造函数SmartPtr<MyClass> sp2 = sp1; // 拷贝构造函数SmartPtr<MyClass> sp3(rc1); // 普通构造函数SmartPtr<MyClass> sp4(sp1); // 拷贝构造函数MyClass *rc2 = new MyClass();sp3 = rc2; // 赋值运算符sp4 = sp3; // 赋值运算符cout << (*sp1).MyFoo() << endl; // 像指针一样操作cout << sp1->MyFoo() << endl;vector<SmartPtr<MyClass>> v; // 在vector中的表现v.push_back(sp1);v.push_back(sp2);v.push_back(sp3);v.push_back(sp4);}_CrtDumpMemoryLeaks();}

2. C++自带智能指针研究