含指针变量的类需重新声明拷贝构造函数和赋值操作符

看下面一个表示string对象的类:

// 一个很简单的string类

class string

{

public:
string(const char *value);
~string();

... // 没有拷贝构造函数和operator=

private:
char *data;
};

string::string(const char *value)
{
if (value) {
data = new char[strlen(value) + 1];
strcpy(data, value);
}
else {
data = new char[1];
*data = '\0';
}
}

inline string::~string()

{ delete [] data; }


请注意这个类里没有声明赋值操作符和拷贝构造函数。这会带来一些不良后果。

如果这样定义两个对象:


string a("hello");
string b("world");

其结果就会如下所示:


a: data——> "hello\0"
b: data——> "world\0"

对象a的内部是一个指向包含字符串"hello"的内存的指针,对象b的内部是一个指向包含字符串"world"的内存的指针。如果进行下面的赋值:

b = a;


因为没有自定义的operator=可以调用,c++会生成并调用一个缺省的operator=操作符(见条款45)。这个缺省的赋值操作符会执行从a的成员到b的成员的逐个成员的赋值操作,对指针(a.data和b.data) 来说就是逐位拷贝。把b->data 指向 a->data指向的内存,但是b->data原来的空间却仍然存在,并没有释放!

这种情况下至少有两个问题。

第一,b曾指向的内存永远不会被删除,因而会永远丢失。这是产生内存泄漏的典型例子

第二,现在a和b包含的指针指向同一个字符串,那么只要其中一个离开了它的生存空间,其析构函数就会删除掉另一个指针还指向的那块内存。


stringa("hello");                // 定义并构造 a

                                      // 开一个新的生存空间
 
stringb("world");            // 定义并构造 b

  ...

  b =a;                             // 执行 operator=
 
                                      // 丢失b的内存

                                    // 离开生存空间
 
                                     // 调用b的析构函数

string c =a;                    // c.data 的值不能确定
    
                                 // a.data 已被删除



例子中最后一个语句调用了拷贝构造函数,因为它也没有在类中定义,c++以与处理赋值操作符一样的方式生成一个拷贝构造函数并执行相同的动作:对对象里的指针进行逐位拷贝。这会导致同样的问题,但不用担心内存泄漏,因为被初始化的对象还不能指向任何的内存。比如上面代码中的情形,当c.data用a.data的值来初始化时没有内存泄漏,因为c.data没指向任何地方。不过,假如c被a初始化后,c.data和a.data指向同一个地方,那这个地方会被删除两次:一次在c被摧毁时,另一次在a被摧毁时。


牢记:只要类里有指针变量就得自己写拷贝构造函数和赋值函数,但是你确定用不着这些函数时,可以把这些函数做private声明而不去实现它,这就防止了会有人去调用它们,也防止了编译器去生成它们。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值