以下摘自林銳的高質量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