深淺拷貝
編譯器預設提供的拷貝是淺拷貝,将一個對象中所有成員變量的值拷貝到另一個對象。
然而,如果某個對象成員是指針類型,隻會拷貝指針中存儲的位址值,并不會拷貝指針指向的記憶體空間。
當通過構造函數指派時,類外部指針和類内部指針指向同一塊記憶體空間,會互相幹擾。
class Student {
private:
char* m_name;
int m_age;
public:
Student(char* name, int age):m_name(name),m_age(age){}
void output() {
cout << m_name << " " << m_age << endl;
}
void changeName() {
m_name[0] = 'x';
}
};
int main() {
char name[10] = "blackcat";
Student* stu1 = new Student(name, 10);
stu1->output();
cout << name << endl;
stu1->changeName();
stu1->output();
cout << name << endl;
return 0;
}
不僅兩個指針可以互相修改記憶體資料,棧空間資料很可能會釋放,導緻堆空間指向資料消失。
解決方案
在堆空間再開辟一塊記憶體,把棧空間資料拷貝過來,防止互相幹擾。
Student(char* name, int age){
m_name = new char[strlen(name) + 1]();
strcpy(m_name, name);
m_age = age;
}
~Student() {
if (m_name == NULL) return;
delete[] m_name;
m_name = NULL;
}
拷貝構造問題
在堆空間備份棧空間資料,可以起到指針變量指派時進行資料隔離。
然而,如果遇到拷貝構造會出現什麼問題呢?
如果成員變量是指針類型,拷貝構造會導緻多個對象儲存同一個指針,不同對象的指針指向同一塊記憶體空間,是以可以互相修改,并且析構時,會對同一塊記憶體空間進行多次析構,使得程式發生異常。
析構釋放時會出現 double free 情況。
深拷貝
将原指針指向的記憶體空間拷貝一份到新的空間。
private:
char* m_name;
int m_age;
void copyName(const char* name) {
if (name == NULL) return;
m_name = new char[strlen(name) + 1]();
strcpy(m_name, name);
}
public:
Student(const char* name, int age) {
copyName(name);
m_age = age;
}
Student(const Student& stu) {
copyName(stu.m_name);
m_age = stu.m_age;
}