浅拷贝
二进制复制不复制指向的内存单元,这导致两个 MyString 对象指向同一个内存单元。函数 UseMyString( )返回时,变量 str 不再在作用域内,因此被销毁。为此,将调用 MyString 类的析构函数, 而该析构函数使用 delete[]释放分配给 buffer 的内存,这将导致 main( ) 中的对象 sayHello 指向的内存无效,而等 main( )执行完毕时,sayHello 将不再在作用域内,进而被销 毁。但这次不再有有效的内存地址调用 delete(销毁 str 时释放了该内存,导致它无效)。正是 这种重复调用 delete 导致了程序崩溃。
eg:
//Mystring 类声明
class MyString
{
private:
char* buffer; //指针成员
public:
MyString(const char* initString) // constructor
{
buffer = NULL;
cout << "Default constructor: creating new MyString" << endl;
if(initString != NULL)
{
buffer = new char [strlen(initString) + 1];
strcpy(buffer, initString);
cout << "buffer points to: 0x" << hex;
cout << (unsigned int*)buffer << endl;
}
}
//以Mystring类值做参数
//编译器以二进制复制指针buffer
//这时新创建的对象 str.buffer 与 main函数中Mystring类对象的buffer指针指向同一片
//内存空间,当函数结束,析构函数销毁buffer指向的内存,main 中的对象当程序结束释放
//时,指向的空间已经销毁,导致出错。
void UseMyString(MyString str)
{
cout << "String buffer in MyString is " << str.GetLength();
cout << " characters long" << endl;
cout << "buffer contains: " << str.GetString() << endl;
return;
}
深拷贝
使用复制构造函数确保深复制
复制构造函数是一个重载的构造函数,由编写类的程序员提供。每当对象被复制时,编译器都将 调用复制构造函数。 为 MyString 类声明复制构造函数的语法如下:
class MyString
{
MyString(const MyString& copySource); // copy constructor
};
MyString::MyString(const MyString& copySource)
{
// Copy constructor implementation code
}
定义一个复制构造函数,确保对动态分配的缓冲区进行深复制
class MyString
{
private:
char* buffer;
public:
MyString() {}
MyString(const char* initString) // constructor
{
buffer = NULL;
cout << "Default constructor: creating new MyString" << endl;
if(initString != NULL)
{
buffer = new char [strlen(initString) + 1];
strcpy(buffer, initString);
cout << "buffer points to: 0x" << hex;
cout << (unsigned int*)buffer << endl;
}
}
MyString(const MyString& copySource) // Copy constructor
{
buffer = NULL;
cout << "Copy constructor: copying from MyString" << endl;
if(copySource.buffer != NULL)
{
// allocate own buffer
buffer = new char [strlen(copySource.buffer) + 1];
// deep copy from the source into local buffer
strcpy(buffer, copySource.buffer);
cout << "buffer points to: 0x" << hex;
cout << (unsigned int*)buffer << endl;
}
}
MyString operator+ (const MyString& addThis)
{
MyString newString;
if (addThis.buffer != NULL)
{
newString.buffer = new char[GetLength() + strlen(addThis.buffer) + 1];
strcpy(newString.buffer, buffer);
strcat(newString.buffer, addThis.buffer);
}
return newString;
}
// Destructor
~MyString()
{
cout << "Invoking destructor, clearing up" << endl;
delete [] buffer;
}
int GetLength()
{ return strlen(buffer); }
const char* GetString()
{ return buffer; }
};
void UseMyString(MyString str)
{
cout << "String buffer in MyString is " << str.GetLength();
cout << " characters long" << endl;
cout << "buffer contains: " << str.GetString() << endl;
return;
}
int main()
{
MyString sayHello("Hello from String Class");
UseMyString(sayHello);
return 0;
}
输出结果说明,buffer指向的空间不同,这样析构函数释放空间不会再出错
复制构造函数确保下面的函数调用进行深复制:
MyString sayHello("Hello from String Class");
UseMyString(sayHello);
然而,如果通过赋值进行复制时,结果如何呢?
MyString overwrite("who cares? ");
overwrite = sayHello;
由于没有提供复制赋值运算符 operator=,编译器提供的默认复制赋值运算符将导致浅复制。