以下摘自林锐的高质量C++编程:
如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String 的两个对象a,b 为例,假设a.m_data 的内容为“hello”,b.m_data 的内容为“world”。
现将a 赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。这将造成三个错误:一是b.m_data 原有的内存没被释放,造成内存泄露;二是b.m_data 和a.m_data 指向同一块内存,a 或b 任何一方变动都会影响另一方;三是在对象被析构时,m_data 被释放了两次。
代码如下:
#ifndef STRING_H_
#define STRING_H_
#include <iostream>
#include <string.h>
using namespace std;
class String
{
public:
String()
:data_(new char[1])
{
*data_ = ' ';
}
String(const char* str)
:data_(new char[strlen(str)+1])
{
strcpy(data_, str);
}
void set_data(const char* str)
{
char *tmp = data_;
while(*tmp)
{
*tmp++ = *str++;
}
}
void output_data(void)
{
cout << data_ << endl;
}
~String()
{
delete []data_;
}
friend ostream& operator <<(ostream& os, const String &str);
private:
char *data_;
};
ostream& operator <<(ostream& os, const String &str)
{
os << str.data_;
return os;
}
#endif /* STRING_H_ */
#include <iostream>
#include "String.h"
using namespace std;
int main()
{
String a("hello");
String b(a);
cout << "the string a is: " << a << endl;
cout << "the string b is: " << b << endl;
a.set_data("world");
cout << "the string a is: " << a << endl;
cout << "the string b is: " << b << endl;
}
在g++下编译时,会在输出后显示:Aborted(core dumped)。输出:
the string a is: hello
the string b is: hello
the string a is: world
the string b is: world
由string b的data_也是'world'说明:a 和 b的data_占用了同一块内存,是位拷贝。
正确的string类,包含自定义的复制构造函数和赋值操作符:
#ifndef STRING_H_
#define STRING_H_
#include <iostream>
#include <string.h>
using namespace std;
class String
{
public:
//default constructor
String()
:data_(new char[1])
{
*data_ = ' ';
}
String(const char* str)
:data_(new char[strlen(str)+1])
{
strcpy(data_, str);
}
//copy constructor
String(const String &str)
{
data_ = new char[strlen(str.data_)+1];
strcpy(data_, str.data_);
}
//operator =
String & operator =(String &str)
{
if(this == &str)
return *this;
delete []data_;
data_ = new char[strlen(str.data_)+1];
strcpy(data_, str.data_);
return *this;
}
void set_data(const char* str)
{
char *tmp = data_;
while(*tmp)
{
*tmp++ = *str++;
}
}
void output_data(void)
{
cout << data_ << endl;
}
~String()
{
delete []data_;
}
friend ostream& operator <<(ostream& os, const String &str);
private:
char *data_;
};
ostream& operator <<(ostream& os, const String &str)
{
os << str.data_;
return os;
}
#endif /* STRING_H_ */
执行main函数的输出:
the string a is: hello
the string b is: hello
the string a is: world
the string b is: hello