当前位置:天才代写 > tutorial > C语言/C++ 教程 > c++智能指针的建设

c++智能指针的建设

2017-11-05 08:00 星期日 所属: C语言/C++ 教程 浏览:432

副标题#e#

zero 坐在餐桌前,机器的反复“夹菜 -> 品味 -> 吞咽”的行动序列,脸上用无形的大字写着:我心不在焉。在他的劈面坐着 Solmyr ,慢条斯理的吃着他那份午餐,维持着他一贯很有涵养的形象 ——— 可能凭据 zero 这些熟悉他本质的人的说法:假象。

“怎么了 zero ?胃口欠好么?”,根基填饱肚子之后,Solmyr 以为好像应该体贴一下他的学徒了。

“呃,没什么,只是 …… Solmyr ,C++ 为什么不支持垃圾收集呢?(注:垃圾收集是一种机制,担保动态分派了的内存块会自动释放,Java 等语言支持这一机制。)”

Solmyr 叹了口吻,用一种安静的眼神盯着 zero :“是不是在 BBS 上和人吵 C++ 和 Java 哪个更好?并且吵输了?我早汇报过你,这种争论再无聊不外了。”

“呃 …… 是”,zero 不得不认可 ——— Solmyr 的眼神固然一点也不锐利,可是却莫名其妙的让 zero 发生了微微的惊骇感。

“并且,谁汇报你 C++ 不支持垃圾收集的?”

“啊!Solmyr 你不是恶作剧吧?!”

“zero 你得转变一下见识。我问你,C++ 支不支持可以动态改变巨细的数组?”

“这 …… 好象也没有吧?”

“那 vector 是什么对象?”

“呃 ……”

“支持一种特性,并不是说非得把这个特性加到语法里去,我们也可以选择用现有的语言机制实现一个库来支持这个特征。以垃圾收集为例,这里我们的任务是要担保每一个被动态分派的内存块都可以或许被释放,也就是说 ……”,Solmyr 不知从那边找出了一张纸、一支笔,写到:

int* p = new int; // 1 delete p; // 2

“也就是说,对付每一个 1 ,我们要担保有一个 2 被挪用,1 和 2 必需成对呈现。我来问你,C++ 中有什么对象是由语言自己担保必然成对呈现的?”

“……”,zero 暴露了尽力搜索影象的心情,不外很明明一无所获。

“提示一下,和类的建设有关。”

“哦!结构函数与析构函数!”

“正确。惋惜普通指针没有结构函数与析构函数,所以我们必需要写一个类来加一层包装,最简朴的就象这样:”

class my_intptr
{
public:
int* m_p;

my_intptr(int* p){ m_p = p; }
~my_intptr(){ delete m_p; }
};

…………

my_intptr pi(new int);
*(pi.m_p) = 10;

…………


#p#副标题#e#

“这里我们可以安心的利用 my_intptr ,不消担忧内存泄漏的问题:一旦 pi 这个变量被销毁,我们知道 pi.p 指向的内存块必然会被释放。不外假如每次利用 my_intptr 都得去会见它的成员未免太贫苦了。为此,可以给这个类加上重载的 * 运算符:”

class my_intptr
{
private:
int* m_p;

public:
my_intptr(int* p){ m_p = p; }
~my_intptr(){ delete m_p; }

int& operator*(){ return *m_p; }
};

…………

my_intptr pi;
*pi = 10;
int a = *pi;

…………

“此刻是不是看起来 my_intptr 就像是一个真正的指针了?正因为如此,这种技能被称为智能指针。此刻我问你,这个类还缺少哪些对象?”

zero 皱着眉头,眼睛一眨一眨,看上去就像一台慢速电脑正在辛苦的往它的硬盘上拷贝文件。很久,zero 抬起头来,不太确定的说:“是不是还缺少一个拷贝结构函数和一个赋值运算符?”

“说说为什么。”,Solmyr 显然不规划就这样放过 zero.

“因为 …… 我记得没错的话 …… 《50 诫 》(注:指《Effective C++ 2/e》一书)中提到过,假如你的类内里有指针指向动态分派的内存,那么必然要为它写一个拷贝结构函数和一个赋值运算符 …… 因为 …… 不然的话,一旦你做了赋值,会导致两个工具的指针指向同一块内存。对了!假如是上面的类,这样一来会导致同一个指针被 delete 两次!”

“正确。那么我们应该奈何来实现呢?”

“这简朴,我们用 memcpy 把方针指针指向的内存中的内容拷贝过来。”

“假如我们的智能指针指向一个类的工具怎么办?留意,类的工具中大概有指针,不能用 memcpy.”

“那 …… 我们用拷贝结构的步伐。”

“假如我们的智能指针指向的工具不能拷贝结构怎么办?它大概有一个私有的拷贝结构函数。”

“那 ……”,zero 顿了一顿,抉择诚恳认可,“我不知道。”

“问题在哪你知道么?在于你没有把智能指针看作指针。想象一下,假如我们对一个指针做赋值,它的寄义是什么?”

#p#分页标题#e#

“呃,我大白了,在这种环境下,应该想步伐让两个智能指针指向同一个工具 …… 但是 Solmyr ,这样以来岂不是仍然要对同一个工具删除两遍?”

#p#副标题#e#

“是的,我们得想步伐办理这个问题,步伐不但一种。较量好的一种是为每个指针维护一个引用计数值,每次赋值可能拷贝结构,就让计数值加一,这意味着指向这个内存块的智能指针又多了一个;而每有一个智能指针被销毁,就让计数值减一,这意味着指向这个内存块的智能指针少了一个;一旦计数值为 0 ,就释放内存块。象这样:”

class my_intptr
{
private:
int* m_p;
int* m_count;

public:
my_intptr(int* p)
{
m_p = p;
m_count = new int; // 初始化计数值为 1
*m_count = 1;
}
my_intptr(const my_intptr& rhs) // 拷贝结构函数
{
m_p = rhs.m_p; // 指向同一块内存
m_count = rhs.m_count; // 利用同一个计数值
(*m_count)++; // 计数值加 1
}
~my_intptr()
{
(*m_count)--; // 计数值减 1
if( *m_count == 0 ) // 已经没有此外指针指向该内存块了
{
delete m_p;
delete m_count;
}
}

my_intptr& operator=(const my_intptr& rhs)
{
if( m_p == rhs.m_p ) // 首先判定是否原来就指向同一内存块
return *this; // 是则直接返回

(*m_count)--; // 计数值减 1 ,因为该指针不再指向本来内存块了
if( *m_count == 0 ) // 已经没有此外指针指向本来内存块了
{
delete m_p;
delete m_count;
}

m_p = rhs.m_p; // 指向同一块内存
m_count = rhs.m_count; // 利用同一个计数值
(*m_count)++; // 计数值加 1
}

…………
};

#p#副标题#e#

“其他部门没有什么太大变革,我不费事了。此刻想象一下我们奈何利用这种智能指针?”,Solmyr 放下了笔,再次拿起了筷子,有些可惜的发明他爱吃的肉丸子已经冷了。

zero 想象着,有些迟疑。“我们 …… 可以用 new int 表达式作为结构函数的参数来结构一个智能指针,然后 …… 然后我们可以任意的赋值,”,他开始抓住了思路,越说越快,“任意的用已经存在的智能指针来结构新的智能指针,智能指针的赋值运算符、拷贝结构函数和析构会担保计数值始终便是指向该内存块的智能指针数。”zero 好像大白了他看到了奈何的成果,开始感动起来:“然后一旦计数值为 0 被分派的内存块就会释放!也就是说 …… 有指针指向内存块,它就不释放,一旦没有,它就自动释放!太棒了!我们只要一开始正确的初始化智能指针,就可以象普通指针那样利用它,并且完全不消担忧内存释放的问题!太棒了!”zero 感动的大呼:“这就是垃圾收集!Solmyr !我们在饭桌上实现了一个垃圾收集器!”

Solmyr 很明明没有分享 zero 的感动:“我在用饭,你能不能不要大呼‘饭桌上实现了一个垃圾收集器’这种倒胃口的话?”顿了一顿,Solmyr 带着他招牌式的坏笑,以一种可恶的口气说道:“并且请留意一下本身的形象。”

“嗯?”,zero 回过神来,发明本身不知什么时候站了起来,而整个餐厅里的人都在看着他嘿嘿偷笑,这让他感受本身像个傻瓜。

zero 红着脸坐下,压低了声音问 Solmyr :“不外 Solmyr ,这确实是一个的垃圾收集机制啊,只要我们把这个类改成 …… 嗯 …… 改成模板类,象这样:”zero 抓过了纸笔,写到:

template <typename T>
class my_ptr
{
private:
T* m_p;
int* m_count;
…………
};

“它不就能支持任意范例的指针了吗?我们就可以把它用在任那里所。”

Solmyr 摇了摇头:“不,你把问题想的太简朴了。对付简朴的范例,这个类确实可以处理惩罚的很好,但实际环境是很巨大的。思量一个典范环境:类 Derived 是类 Base 的派生类,我们但愿这样赋值:”

Base* pb;

Derived pd;

…………

pb = pd;

“你倒说说看,这种环境,奈何改用上面这个智能指针来处理惩罚?”

“……”,zero 沉默沉静了。

#p#分页标题#e#

“要实现一个完整的垃圾收集机制并不容易,因为有很多细节要思量。”,Solmyr 开始总结了,“不外,根基思路就是上面说的这些。值得名誉的是,今朝已经有了一个相当成熟的‘引用计数’智能指针,boost::shared_ptr.大大都环境下,我们都可以利用它。别的,除了智能指针之外,尚有一些技能也可以或许辅佐我们避开释放内存的问题,好比内存池。可是,要害在于 ——— ”

Solmyr 再度用那种安静的眼神盯着 zero :

“身为 C/C++ 措施员,必需有缔造力。那种躺在语言机制上不思进取的人,那种必需要靠语法强制才知道奈何编程的人,那种没有别人汇报他该干什么就无所适从的人,不适合这门语言。”

 

    关键字:

天才代写-代写联系方式