C++为我们提供了默认的复制构造函数,赋值函数和析构函数,使用的全部是“浅复制”,即仅仅复制栈上的数据。换句话说,如果我们涉及到了对堆数据的操作,这些函数都必须我们自己重新来写。我很郁闷为什么在编译的时候,C++不能自己发现构造函数使用了堆操作,从而提醒不要使用默认的这三个函数。也许是因为要编译器做到智能的判断很难吧。用new...delete或许很容易看出来,但是更多的函数调用,特别是涉及到C风格的函数的时候,真的很难判断哪些函数使用到了堆操作。
而这三个函数的作用可以说是巨大的!析构就不说了,析构可以说是C++永远的痛。复制构造函数用得最多的地方,恐怕就是成员初始化列表的时候,这几乎是在一个类成员数据使用到另外一个类对象时候的唯一方法。而赋值函数则是把数据从语句体(“{}”对,循环,判断)中带出的最简单方法——虽然我们现在可以很方便的使用vector。
这里先说说复制构造函数吧。如果遗漏申明,又不慎用到,比如这个例子:
#include <iostream>
#include <vector>
class A
{
private:
int a;
public:
A(int _a): a(_a)
{
std::cout << "A created!\n";
}
/*
A(const A& copy): a(copy.a)
{
std::cout << "A copy created!\n";
}
*/
~A()
{
std::cout << "A destroyed!\n";
}
void show() const
{
std::cout << a << std::endl;
}
};
int main(int argc, char* argv[])
{
A a(1);
A b(a);
return 0;
}
那么,结果运行就会出现貌似创建一次,但是却销毁了两次的假象。这当然是不可能发生的,但是郁闷的是,C++中的构造和析构不总是成对出现的,比如我们前面说到的手动显式调用析构函数的情况。所以,如果放在大的项目中,这为我们的调试带来更多的困难。
所以,结论是,如果A类构造具有堆操作,有可能把A类作为B类的成员数据,B类又有可能通过成员初始化列表构造A对象,请一定别忘记手写复制构造函数。
posted on 2008-04-14 11:50
lf426 阅读(524)
评论(0) 编辑 收藏 引用 所属分类:
语言基础、数据结构与算法