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;
…………
“这里我们可以放心的使用 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;
…………