您的位置:首页 > 编程语言 > C语言/C++

c++ 复制控制和智能指针实现

2016-06-04 21:02 337 查看

1.复制控制场合

C++复制控制提供对象复制时的行为自定义,主要分如下三种

a).复制构造函数

复制构造函数,顾名思义就是在复制对象时会调用的构造函数,很多时候隐式调用的,包含如下:

[1].声明类对象时同时给一个初始化值,此时叫复制初始化



Class A;

Class B=A;

[2].函数形参为传值,返回值为传值时



void func(Class A);

Class func();

[3].容器初始化时,指明容器个数时,此时会先生成一个临时对象,然后将此对象复制给其他的对象



vector<Class> A(5);

[4].数组形式初始化时,会一一复制对应对象



Class A[] = {A1, A2, A3};

b).赋值重载函数

赋值时,对于一般的都是直接使用合成赋值函数。但是对于成员变量为指针、对象或复制时希望完成其他附加操作的均需自己来处理赋值行为。

c).析构函数

最简单的就是自动释放成员指针指向的内存了。

2.复制控制实现

如下为复制控制的实现

class CCopyControl
{
public:
CCopyControl(int nData=0);

CCopyControl(const CCopyControl& c);				//复制构造函数
CCopyControl& operator=(const CCopyControl& c);		//赋值重载函数
~CCopyControl();									//析构函数

private:
int m_nData;
int *m_pData;

void CopyData(const CCopyControl& c);
void DeleteData();
};

//默认构造函数
CCopyControl::CCopyControl( int nData/*=0*/ )
{
m_nData = nData;
m_pData = new int(nData);
}

//复制构造函数
CCopyControl::CCopyControl( const CCopyControl& c )
{
CopyData(c);
}

//赋值重载函数
CCopyControl& CCopyControl::operator=( const CCopyControl& c )
{
if (this != &c)
{
DeleteData();
CopyData(c);
}

return *this;
}

//析构函数
CCopyControl::~CCopyControl()
{
DeleteData();
}

//复制数据
void CCopyControl::CopyData( const CCopyControl& c )
{
this->m_nData  = c.m_nData;
this->m_pData = new int(c.m_nData);	//深拷贝
}

//删除数据
void CCopyControl::DeleteData()
{
if (!m_pData)
{
delete m_pData;
m_pData = NULL;
}
}


需要注意点如下:

1.常见三种复制是一起出现的,即需要自定义一种复制行为时,往往另外两种也需要自定义

2.需要禁止复制时,必须显式地声明其复制构造函数为 private(其友元和成员依然可以复制)

3.如果要连友元和成员的复制也禁止,就可以声明一个private的复制构造函数但不对它进行定义。(如果复制类对象会提示编译错误,如果成员和友元尝试复制就会导致链接错误)

4.在实现时其实赋值重载函数是包含复制构造函数和析构函数功能的,此时可以将复制和析构功能单独做到两个私有函数中,如演示代码中的CopyData和DeleteData

3.智能指针实现

很自然想到,通过复制控制我们可以给指针包上一层壳,来管理指针对应内存的开辟和释放,这就是所谓的“智能指针”。

可以看到前面演示时赋值过程指针为深拷贝,重新开辟了新的内存,复制的只是指针内容;但是为了实现智能指针,则必须共享指针,此时是浅拷贝,但是如果要实现自动释放内存的功能,此时需要在对象析构函数时释放内存,这样就存在多次释放的问题了,为此引入引用计数,只有引用计数为0时才真正释放内存。

下面是我实现的一个简单的智能指针类

template <class T>
class CMySmartPtr
{
public:
/*构造函数*/
CMySmartPtr(T* pT)
{
pCountT = new CCountT(pT);
}

CMySmartPtr()
{
pCountT = NULL;//默认指针为空
}

/*复制控制*/
~CMySmartPtr()
{
DeleteData();
}

CMySmartPtr(const CMySmartPtr& p)
{
CopyData(p);
}

CMySmartPtr& operator=(const CMySmartPtr& p)
{
if (this != &p)//注意自身对自身赋值的情况
{
DeleteData();
CopyData(p);
}

return *this;
}

/*指针*和->解引用*/
T& operator*()
{
return *(this->pCountT->pT);
}

T* operator->()
{
return this->pCountT->pT;
}

private:
//装饰类,为待管理的指针增加引用计数
class CCountT
{
public:
CCountT(T* pT)
{
this->pT = pT;
this->nCount = 1;
}

~CCountT()
{
delete pT;
}

T* pT;
int nCount;
};

//统一共享的指针,依靠引用计数来释放
private:
CCountT *pCountT;

void CopyData(const CMySmartPtr& p)
{
p.pCountT->nCount++;
this->pCountT = p.pCountT;
}

void DeleteData()
{
if (pCountT && --pCountT->nCount==0)
{

delete pCountT;
pCountT = NULL;
}
}
};


这里注意如下几点:

1.创建一个私有类,专门用来包装实际指针pT,为其提供引用计数

2.注意赋值时需要考虑注意自身对自身赋值的情况

3.这里只是考虑了简单的单线程,多线程可能还存在问题

本文完整演示代码下载链接

原创,转载请注明来自http://blog.csdn.net/wenzhou1219
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: