如果自己构造一个类,而且其中涉及到了动态内存分配,则十分有必要给出该类的copy构造函数和operator=。因为这样可以放置内存操作问题。
比如创建一个新的类CItem,如下所示。
class CItem
{
public:
CItem();
~CItem();
char* pData;
}
CItem::CItem()
{
pData = new char[64];
strcpy(pData, “Hello”);
}
CItem::~CItem()
{
if (NULL != pData)
{
delete pData;
pData = NULL;
}
}
如果没有copy构造函数,系统会调用CItem的每个变量的copy构造函数来为每个变量进行copy操作;如果变量也没有copy构造函数,则调用变量的变量的copy构造函数来进行赋值操作,以此类推。如果变量为内建类型(int, char等类型),则直接对内建类型变量进行bitwise copy(按位拷贝)。operator=的操作也是这样。这样就会有个问题:
CItem a;
CItem b(a); // 或CItem b; b = a;
上面这段代码中,b因为没有copy构造函数(operator=),故系统首先调用CItem的缺省构造函数,为b.pData开辟了内存空间,接着进行了赋值操作,按照上面说的原则,执行了b.pData = a.pData操作,b.pData原来的空间没有被释放,但b.pData却指向了a.pData的内存空间。问题出现了,首先,原来b.pData的空间成了死内存,而因为b.pData和a.pData都指向了相同的内存空间,所以,如果一个被释放时,另一个将指向一个无效的空间。
还有一个问题:强制类型转换时,也会出现类似的问题。如:
CItem a;
a = (CItem)(*b); // b是一个包含CItem类型变量的一个指针,如list的iterator
这种情况下,系统会先自动生成一个CItem变量,来保存*b对应的CItem变量,然后用这个自动产生的变量给a赋值,赋值结束后马上释放自动产生的变量。如果没有定义copy构造函数或operator=的话,*b中包含的CItem变量的pData的内存将被释放,a.pData和(*b).pData将指向无效地址。
综上所述,为一个类创建 copy 构造函数和重载 operator= 还是很有必要的。