C 中的指针(三) 智能指针
2008-02-23 05:04:35来源:互联网 阅读 ()
原帖及讨论:http://bbs.bc-cn.net/dispbbs.asp?BoardID=56&ID=92844
Smart Pointer是C 中的一个大题目,要说清楚他的任何好处很需要费点力气。我就一个功能一个功能的说。有我理解不透的地方希望大家指点。
1.copy-to-write
当生成一个C object的时候假如这个class很大,这个object会占用很多空间。那么每生成一个就占用一片空间,这样会占用很多系统资源。同时降低效率。一个解决方法就是对用拷贝构造函数生成的object,让他不存储数据,而只存储一个指向原来object数据的指针。这样空间就节省了很多。但问题在于这样两个object完全联结在了一起。假如修改了其中一个,另一个也跟着变了。所以这种方法不可取。这里讲的copy-to-write技术就是解决这类问题的方法。当通过引用一个已有object去拷贝构造新object时,新object只有一个指向已有object的指针。这两个object共享数据。直到其中一个需要修改数据的时候,再把这两块数据分离。这里举一个最简化的例子。假设一个class叫CLargeObject,里面存有很多数据。我们用一个inner class来把任何数据放在一起,叫CData。CData里面存有大量数据,例如一个数据库。这里用最简单的模型来表示,假设只有一个整数int m_nVal; CData里面需要包含另一个变量。叫作索引数目(reference count)。他记录了指向这个CData object的来自CLargetObject类的指针各数。也就是说,总共有多少CLargeObject的object正在引用着当前的CData object。
class CLargeObject
{
private:
struct CData
{
private:
int m_nVal;
int m_nReferenceCount;
}
};
对于每个CLargeObject的object,我们用一个CData类的指针来指向其数据。
CData *m_pData;
CLargeObject至少有两个构造函数。第一个是标准的构造函数,初始化其数据。这时数据是唯一的,所以必须新生成一个CData的object来存储数据。
CLargeObject::CLargeObject(int nVal)
{
m_pData = new Data(nVal);
}
而对于CData类的构造函数而言,初始化他的CLargeObject是第一个指向他的,这一时刻索引数目m_nReferenceCount是1。
CLargeObject::Data::Data(int nVal) : m_nVal(nVal), m_nReferenceCount(1) {}
CLargeObject的第二个构造函数是拷贝构造(copy constructor)。这样生成的object无需有新的数据,和已有的object共享数据就能够了。这是索引数目需要加1。表示又有一个object指向当前的CData了。
CLargeObject::CLargeObject(const CLargeObject &ob) // copy constructor
{
ob.m_pData->m_nReferenceCount ;
m_pData = ob.m_pData;
}
这样CLargeObject就构造好了,使用了可能的最少的内存。下面看看他的析够函数(destructor)。当一个object被delete的时候,他的数据不一定无效,假如别的object还在引用着这个数据,数据需要留下来。当然,数据的索引数目无论如何都要减1。
CLargeObject::~CLargeObject()
{
if (--m_pData->m_nReferenceCount == 0)
delete m_pData;
}
下面看一看赋值操作。先说用已有的CLargeObject赋值给这个CLargeObject。这时当前CLargeObject里面的数据要指向已有的这个object,就搞定了。
CLargeObject& CLargeObject::operator = (const CLargeObject& ob) // copy assignment
{
ob.m_pData->m_nReferenceCount ;
if (--m_pData->m_nReferenceCount == 0)
delete m_pData;
m_pData = ob.m_pData;
return *this;
}
再来看看如何对CLargeObject里面的数据进行真正的修改。这样就一定需要对当前的object单独操作了,否则就影响到了其他指向同一块数据的CLargeObject。这样CData类需要一个新的函数,生成只用于当前CLargetObject的数据。假如当前的引用数目是1,那么当然这个CData就是只用于这个CLargeObject的了。否则就重新new一个CData返回。
Data* CLargeObject::CData::get_own_copy() // clone if necessary
{
if (m_nReferenceCount==1)
return this;
m_nReferenceCount--;
return new Data(m_nVal);
}
CLargeObject修改前用这个函数得到唯一的object,然后对他赋值。
void CLargeObject::SetVal(int nNewVal)
{
m_pData = m_pData->get_own_copy();
m_pData->m_nVal = nNewVal;
}
对于任何可能改变CData值的操作,都需要用这种方法。
下面是只读函数,简单。直接返回值,什么特别的都不用作。
int CLargeObject::GetVal() const
{
return m_pData->m_nVal;
}
这样copy-to-write技术就实现了。下面把完整的程式写一下:
class CLargeObject
{
public:
CLargeObject(int nVal);
CLargeObject(const CLargeObject &ob);
~CLargeObject();
CLargeObject& operator = (const CLargeObject& ob);
void SetVal(int nNewVal);
int GetVal() const;
private:
struct Data
{
public:
Data(int nVal) : m_nVal(nVal), m_nReferenceCount(1) {}
private:
friend class CLargeObject;
Data* get_own_copy() // clone if necessary
{
if (m_nReferenceCount==1)
return this;
m_nReferenceCount--;
return new Data(m_nVal);
}
// control variables.
int m_nReferenceCount;
// actual data portion
int m_nVal;
};
Data *m_pData;
};
CLargeObject::CLargeObject(int nVal)
{
m_pData = new Data(nVal);
}
CLargeObject::CLargeObject(const CLargeObject &ob) // copy constructor
{
ob.m_pData->m_nReferenceCount ;
m_pData = ob.m_pData;
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇: C 中的指针(二) 函数指针
下一篇: 深度探索C 对象模型(1)
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash