当类的成员变量存在指针类型时,如果采用赋值语句将一个该类对象赋给另外一个对象时,默认会采用浅拷贝,也即两个指针类型的成员变量指向同一个地址,这样当对象生命周期结束时会调用析构函数,释放相应的内存地址。但是由于浅拷贝,会导致释放发生两次,如此第二次释放发生时,因为已经被释放过一次,所以程序会奔溃。代码如下:
#include <iostream>
#include <string>
class String{
private:
char* m_Buffer;
unsigned int m_Size;
public:
String(const char* string){
m_Size = strlen(string);
m_Buffer = new char[m_Size +1];
memcpy(m_Buffer, string, m_Size+1);
}
~String(){
delete[] m_Buffer;
}
friend std::ostream& operator<<(std::ostream& stream, const String& string);
};
std::ostream& operator<<(std::ostream& stream, const String& string){
stream << string.m_Buffer;
return stream;
}
void PrintString(const String& string){
std::cout << string <<std::endl;
}
int main(){
String string = "Luobaotai";
String second = string;
PrintString(string);
PrintString(second);
std::cin.get();
}
定义了一个String类,有一个指针类型的成员变量,复写了操作符 <<, 用于支持string打印。由于复写函数需要调用String类的成员变量,所以将其定义为该类的友元函数。最后定义一个功能函数PrintString,供main调用。
编译运行,会发生前述的奔溃。
为了解决这个问题,需要引入深度拷贝。即不再拷贝指针变量地址,而是将指针内容拷贝到一个新的内存地址,建立一个新的指针,如此实现了结偶,使得析构函数调用时不再发生上述错误,代码如下,主要添加了新的构造函数 String(const String& other):
#include <iostream>
#include <string>
class String{
private:
char* m_Buffer;
unsigned int m_Size;
public:
String(const char* string){
m_Size = strlen(string);
m_Buffer = new char[m_Size +1];
memcpy(m_Buffer, string, m_Size+1);
}
String(const String& other)
: m_Size(other.m_Size){
std::cout << "copy string" <<std::endl;
m_Buffer = new char[m_Size +1];
memcpy(m_Buffer, other.m_Buffer, m_Size +1);
}
~String(){
delete[] m_Buffer;
}
friend std::ostream& operator<<(std::ostream& stream, const String& string);
};
std::ostream& operator<<(std::ostream& stream, const String& string){
stream << string.m_Buffer;
return stream;
}
void PrintString(const String& string){
std::cout << string <<std::endl;
}
int main(){
String string = "Luobaotai";
String second = string;
PrintString(string);
PrintString(second);
std::cin.get();
}
ps:PrintString(const String& string)函数参数设置要注意,如果不使用引用,会导致函数调用时多次没必要的拷贝,降低效率,所以一定要加上&符号,使用引用。另外如果不想改变入参对应的值,一定要加上const