
声明
本英文资料源自于 Herb Sutter 创建的“Conversation”栏目,翻译作品供学习交流与参考用途,
不得用于任何商业用途。
文章来源:http://www.gotw.ca
版权归属:Herb Sutter and Jim Hyslop
Herb Sutter
是个独立顾问,也是 ISO/ANSI C++标准委员会的秘书。你可通过 hsutter@acm.org.联系他
Jim Hyslop
Leitch Technology International Inc.资深的软件设计师,你可通过 jim.hyslop@leitch.com 联系
他
对话#01: auto_ptr 再回忆
译 者:toulouse(CSDN)
我刚刚在昨天遇到珍妮,就在人员中转站,现在已经远远在我们脚下了。“我会永远记住
我的第一个工作,”在乘务员检查完我们的安全带后,我对她说。
“想起了什么”
“项目组高级程序员,”我微笑着说,陷入了回忆中。“她是个古怪的家伙,我们都叫她做

Guru。领导不喜欢把新来的程序员分到她的组里;我是当年招聘的四个人中唯一坚持到试
用期结束的。”
珍妮扭过头刚准备问一个问题,这时钟声响起,隆隆的加速声响彻整个机舱,我们的谈
话因此中断了好几分钟,等这截推进器快烧完时,我们已飞离轨道,我给她讲述了工作第
二天发生的故事。
- - - - - - - - - - - - - - - - - - - - - - - - -
我们用早期的 C++语言编程。工作的第二天中午,厌烦了读职工手册,于是我写了一个
工具类,里面包含一个原始指针作为成员变量:
#include "xStruct.h" // definition of struct X
class xWrapper
{
X* xItem;
public:
xWrapper() : xItem(new X) { }
~xWrapper() { delete xItem; }
void dump() { /* dumps xItem to cout */ }
};
当然了,使用这个类的程序由于内存问题总是时不时的崩溃,因为我违反三个重要设计
原则之一:任何时候,只要你提供了析构函数、拷贝构造函数或赋值运算符中的一个,你
通常需要三个都提供。([1]) “所以,”我自言自语道,“我必须自己处理拷贝和赋值问题。简
单地...auto_ptr 有拷贝构造函数和赋值运算符,我可以拿过来用一下。”(你知道早期 C++
程序库中的 auto_ptr,是吗?)
既然 auto_ptr 自动删除它所指向的对象,我只需要改变 xItem 的类型,移去析构函数中的
delete 语句-auto_ptr 会处理其他的事情,对吗?
Class xWrapper
{
auto_ptr<X> xItem;
public:
xWrapper() : xItem(new X) { }
void dump() { /* dumps xItem to cout */ }
};
不幸的是,程序仍要崩溃,这次是由于它试图对空指针进行提领操作。我对这个问题苦
苦思索了半个小时,这时 Guru 碰巧从我这里路过,像芦柴棒一样瘦瘦的她一只手里捧着厚
厚的一本打开的书。 她来得――我的意思是她来得太不是时候了,真是怕什么来什么,实

际上,这简直称得上诡异了。
“哦,你在看什么?”我指着书问,想让她的注意力从我的屏幕挪开,同时也希望着她能离
开。
Guru 眨了眨眼睛。“Josuttis 的书,”她边温和地说着,边做了个标记并合上书。“年轻人,
你写了些什么啊?”
“我在写这个 wrapper class 时遇到了问题,”我承认道,“我使用了 auto_ptr 成员,但是在
测试时,不知为什么它的指针重置为 null。”
“把你的代码给我看一下,”Guru 说。我把屏幕转向她。“所有权,”仅仅扫了一眼,她立
刻说,
这回轮到我眨眼睛了。
“所有权,孩子;你的问题是所有权语义学。一臣不事二主,没有指针可以同时给两个
auto_ptr 使用。”
她的话虽然很怪,却使我意识到了自己的错误。“哦,是的,”我答道。“当你拷贝一个
auto_ptr 的时候,原来的那个放弃了所有权,重置为 null。Xwrapper 的拷贝构造函数使用了
那个缺省的行为,所以原来 xWrapper 对象的 auto_ptr 被重置,于是我存取它的时候,实际
上是在提领一个 null 指针。”
“对的,”Guru 说。“你能使用标准里已有的代码,这很好,不过使用的时候要小心。对
于 xWrapper 来说,你还是必须自己写拷贝构造函数和赋值运算符。”
“但是,我没法用 auto_ptr 的拷贝构造函数和赋值运算符来实现他们啊,因为 auto_ptr 自
己的版本无法正确的……-哦。有办法了。我可以用 auto_ptr 的提领运算符访问其拥有的
对象。”我很快写下了下面的两个函数:
XWrapper::xWrapper(const xWrapper& other)
: xItem(new X(*other.xItem))
{ }
xWrapper& xWrapper::operator=(const xWrapper &other)
{
*xItem = *other.xItem;
}
“嗨,cool。”我喜欢这个实现,“我甚至不需要在赋值运算符里检查自我赋值。”
“很好。”

我应该就此打住,闭紧嘴巴,可惜我当时正得意着呢:“使用 auto_ptr 很容易出错。如果
在我实际上并不想发生所有权转移时,它可以告诉我它将试图转移所有权,那有多好啊…
…”。”
“冷静一下!”Guru 打断了我。“这不是 auto_ptr 的错。如果你想达到这个效果,你应该明
确地说明你不想 auto_ptr 被拷贝。”
“但是怎么去做呢?这是不可能的。”
“可能的。记住 const 修饰符的使用。声明一个 auto_ptr 不可变的方法是使它成为 const。
假如你让成员成为一个 const,编译器就不能不声不响地产生 xWrapper 对象的一个拷贝。
或者,你可以使用一个也许叫 strict_auto_ptr 的修正版本,这样编译器就不会错误地拷贝和
赋值 xWrapper。当然,在这种情况下,让它成为 const 比较简单和有效率。” ([2])
她离开的时候又重新打开 Josuttis 的书继续看了起来,边走边心不在焉地和我说这话。
她和她的声音慢慢地远去:“要注意的是,我的孩子...auto_ptr 是一个有用的工具,但是就
象你刚才发现的那样,它不是万能的。好好琢磨 Josuttis chapter 4.[3],永远不要在标准程
序库的容器中用 auto_ptr,如 vector<auto_ptr>,因为 auto_ptr 的拷贝和赋值不能达到标准的
要求。此外,永远不要用 auto_ptr 指向对象数组,因为 auto_ptr 的析构函数用 non-array
delete 删除所拥有的对象;对于对象数组来说,可以用一个 vector。程序库...”
这时她转了个弯,消失了。这只是我工作的第二天;我告诉自己,不能空闲下来,我应
该不断地学习,前面的路还很长!
- - - - - - - - - - - - - - - - - - - - - - - - -
“不可思议,”珍妮说,喝着咖啡,此时飞船已飞离了泰兰的交通控制区域,并继续加速 ,
“那么,你离开了吗?”
“她...我不确定为什么,”我坦白承认,“这种事发生了好几次。我也想和其他人那样在试
用期离开,尽管他可能对我有好的影响。你曾经和这样的怪人工作过吗?”
“嗯,我想也有一些。”
这不是最后一次我和珍妮谈论 Guru 或其他更令人高兴的事。
对话:#02 空引用
译 者:夏天

在船上,你最后想感受的就是海风了。我和珍妮碰巧很不凑巧,最接近事故发生地点。
我们费尽力气,将笨重的房门关上,并将其密封,使打破的小房间与外面隔绝。当我们靠
在门上,作深呼吸的时候,汽笛突然停止鸣响.
“他奶奶的,到底怎么回事?”值班驾驶员刺耳的声音穿过了整个船舱。
“小小渗漏而已,先生,”珍妮回答,“我们已封好了那间船厢,问题已解决,没事了。”
“你密封了船厢?为什么它不能自动密封呢?刚才我们不是把门重修了吗?”
珍妮和我对望了一眼。“哦,先生,维修人员都认为这个新的锁闭装置不会有问题,因为
它是刚从工厂出来的,是崭新的,因此他们没有检查它。它是好的,只不过他们没有取下
所有的包装材料,所以它不能自动密封。”
稍停片刻后,珍妮接着说,“对,干得不错。有个维修人员正在赶来。” 接着,恰好在被
打破的船舱前面,我们听到 XO 的声音在说:“约翰逊先生,叫工程部主管到我的船舱来见
我。告诉雷利到...”
我对着珍妮咧嘴一笑,“能听到刚才的对话,我愿意付一个星期的薪水。它提醒了我我们
以前遇到的一个编码安全的问题,这是很久以前的事了...”
- - - - - - - - - - - - - - - - - - - - - - - - -
我的第一份编程工作已干了几个星期了,也熟悉了同一项目组的其他的程序员,其中一
个是鲍勃。几乎在每一个方面,他都与 Guru 形成鲜明对比。鲍勃是个自命不凡的家伙,他
的代码让其他人很难维护,并且经常违反编程的规则。
我已经一头扎进我的第一个项目,鲍勃的任务是对我经手的一些资料进行核查。他来到
我的桌边,拿着一杯咖啡,靠在隔板上,“你的代码由于在你的 helper 函数里存在一个存取
违规而崩溃。”他说,“在 Space Cadet 知道之前,你最好把它改好。”
“Guru 的确是一个优秀的程序员,鲍勃,”我生气了。的确,Guru 是很古怪,在她旁边时,
我也不自在。每次我和她谈话时,我总是不断考虑更新我的概略,但是鲍勃刚才的态度莫
名其妙地激怒了我。
“是,不管怎样,”鲍勃轻蔑地晃了晃杯子,溅出一点咖啡,“总之,你的 helper 函数使用
了空的指针。让我们来看一看。”
“但 helper 函数并没有使用任何指针啊,”我皱了皱眉头。“只不过是一个对 xWrapper 类的
引用而已。”我在文本编辑器里找出代码。它看起来是这样的:
class xWrapper
{