在黑暗中举起探索的火炬的网志
在喧闹、混杂的生活中
你应该与你的心灵和平相处
尽管这世上有很多假冒和欺骗
有很多单调乏味的工作
和众多破灭的梦幻
它仍然是一个美好的世界
记住:你应该努力去追求幸福。
是的,记住:你应该努力去追求幸福。
每个早晨灿烂的太阳升起的时候,
每个人都应
-
2004-04-05
[转载] Solmyr 的小品文系列之八:拷贝 - [C/C++开发专辑]
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
Solmyr 的小品文系列之八:拷贝 Elminster -------------------------------------------------------------------------------- “zero 帮帮忙吧 ~~ ” “灿烂”的笑脸,充满诚意的眼神,再加上点头哈腰的姿势,这三者构成了一尊名为“有求于人”的塑像。 在 QQ 上聊的正欢的 zero 抬起头,看着塑像的作者和材料 ——— pisces ,方圆五十米内唯一的女性程序员 ——— 问道:“什么事?” “我这里有一段 C++ 程序调不通。” “这类问题你应该去问 Solmyr。” “哎呀,别开玩笑了,我哪敢去问他呀!总说我笨!上次问他一个小问题,结果又被训的狗血喷头,哼!”,pisces 显得忿忿不平,“还是你来帮帮我吧,我知道你是部门里有数的高手,肯定搞的定的。帮帮忙吧 ~~” zero 明显的被打动了,于是,在 pisces 的努力下,zero 坐到了 pisces 的计算机前。 “好吧,什么问题?” “是这样的啦,这里有一组 C 风格的 API ,负责管理设备上的字符通信链接。它们是好些年前设计的”,说着,pisces 调出了一些代码: // old C style API typedef int conn_handle; typedef struct { /* ... 打开链接所需的参数和属性 ... */ }conn_attr; conn_handle open_conn(conn_attr* p_attr, char* buf, unsigned int buf_size); void close_conn(conn_handle h); char read_conn(conn_handle h); void write_conn(conn_handle h, char c); ... “枝节的东西不算,主干大概就是这样,一对函数负责打开和关闭,一对函数负责读写。创建链接时候的那个 buf 参数指向一个缓冲区,这个要你自己分配并把长度传进去,和链接一一对应,read_conn/write_conn 会用它做缓冲。我的任务就是写个类把这些 API 包装起来。”,说着 pisces 又调出了另外一段代码: // pisces’ connection class class connection { private: conn_attr m_attr; bool m_opened; int m_bufsize; char* m_buf; conn_handle m_h; ... public: connection(const conn_attr& attr, int bufsize) { m_attr = attr; m_opened = false; m_bufsize = bufsize; m_buf = new char[m_bufsize]; } ~connection() { delete m_buf; } void open() { m_h = open_conn(&m_attr, m_buf, m_bufsize); m_opened = true; } void close() { close_conn(m_h); m_opened = false; } char read() { assert(m_opened); return read_conn(m_h); } void write(char c) { assert(m_opened); write_conn(m_h, c); } ... }; “应该是很简单的,可是不知道怎么回事,用了 connection 类的程序总是时不时的崩溃,说是非法的内存操作。”,pisces 显得很苦恼。 zero 一眼就看出了毛病 ——— 这使他小小的自鸣得意了一下 ——— 但是表面上不动声色,等到他看过 pisces 提供的“总是引发崩溃”的代码段之后,他才开口说到: “这是一个常见的错误 pisces”,zero 尽量使自己的口吻和语气听起来象一个权威,“关于 C++,有一条重要的指导原则:析构函数、拷贝构造函数和赋值运算符三者几乎总是一起出现。也就是说,如果你为一个类写了析构函数,那么往往你不得不再提供一个拷贝构造函数和一个赋值运算符,违反它往往意味着错误。你看这里:” 说着,zero 在屏幕上标出了两行代码: void some_func() { conn_attr attr; ... connection c1(512, attr); connection tmp = c1; ... } “这里对象 tmp 是从 c1 拷贝构造而来的,而你没有定义拷贝构造函数,这使得编译器在这里自动进行按位拷贝,而这使得 tmp 和 c1 的所有成员都相等,包括 m_buf 成员。这样在函数返回时,c1 析构的时候 delete 了一遍 m_buf,在 tmp 析构的时候又 delete 了一遍 ……” “哦!我明白了!” pisces 打断了 zero ,“所以就出现一个非法内存操作,对吧?哎呀,这一条以前在学校里写 string 类的时候遇到过,我怎么会忘了呢?” “对,你只要写一个拷贝构造函数和一个赋值运算符处理一下 m_buf 指针就可以解决这个问题了。这你自己搞的定吧?” “我可以的,多谢了 zero !” zero 心满意足的回到了自己的座位上,开始继续和“你不懂我纤细的心”在 QQ 上探讨“爱情的意义”。可是好景不长,没过多久,本文开头所描述的景象再一次的出现了。 “zero 帮帮忙吧 ~~ ” zero 在心中叹了口气,抬头问道:“又是什么问题,pisces?” “呃,还是那个类。我照你说的给 conn 添加了拷贝构造函数,非法内存操作确实少多了,可还是有,还有好像链接传输数据也有点问题 ———— 你还是过来帮我看看吧 ~~” zero 心不甘情不愿的再次来到了 pisces 的计算机前,翻出 pisces 写的拷贝构造函数检查起来:
http://junglesong.yourblog.org/logs/137069.html
随机文章:
[轉貼] TurboC 2.0 函数中文说明大全(2) 作者:胡颖卓 2004-06-28[转贴] C++常用排序算法 2004-04-29[转载] Solmyr 的小品文系列之一:字符串放在哪里? 2004-04-05[转载] Solmyr和Zero的故事——临时工 2004-04-05[转载] 关于台独分子的笑话 2004-03-23
收藏到:Del.icio.us





