眼見的事實尚有假,背後的言語未必真。---諺語
當使用另一種方式去實現相同的任務時,過往的經驗可以協助你更快速的分析和實現。但有時候經驗也會產生負面影響。
下面的一段例子表示當一個對象以值的形式包含另一個對象時,會自動調用另一個對象的解構函式。
#include <iostream>#include <cstring>using namespace std;class Tyre{char* brand;public:Tyre(Tyre &tyre){cout<<"first construct."<<endl;this->brand = new char[strlen(tyre.brand)+1];strcpy(this->brand,tyre.brand);}Tyre(char* _brand){cout<<"Tyre("<<_brand<<")"<<endl;this->brand = new char[strlen(_brand)+1];strcpy(this->brand,_brand);}~Tyre(){cout<<"Tyre destruct:"<<brand<<endl;delete brand;}void print(){cout<<"This is "<<brand<<" Tyre."<<endl;}};class Car{char* name;Tyre tyre2;public:Car(char* name,Tyre tyre):tyre2(tyre){this->name = new char[strlen(name)+1];strcpy(this->name,name);tyre2.print();}~Car(){cout<<"Car destructor:only delete name"<<endl;delete name;}void print(){cout<<"Car :";this->tyre2.print();}};int main(){Tyre tyre1("g");Car theCar("lexus",tyre1);theCar.print();return 0;}
編譯:gcc -o leak main2.cpp -lstdc++
運行:
D:\workspace\C++\memory_leak\leak2>leakTyre(g)first construct.first construct.This is g Tyre.Tyre destruct:gCar :This is g Tyre.Car destructor:only delete nameTyre destruct:gTyre destruct:g
以引用的方式也一樣自動調用其析構:
//#include <iostream>#include <cstring>using namespace std;class Tyre{char* brand;public:Tyre(char* _brand);~Tyre();void print();};Tyre::Tyre(char* _brand){cout<<"Tyre("<<_brand<<")"<<endl;this->brand = new char[strlen(_brand)+1];strcpy(this->brand,_brand);}Tyre::~Tyre(){cout<<"Tyre destruct:"<<brand<<endl;delete brand;}void Tyre::print(){cout<<"This is "<<brand<<" Tyre."<<endl;}class Car{char* name;Tyre& tyre2;public:Car(char* name,Tyre& tyre);~Car();void print();};Car::Car(char* name,Tyre& tyre):tyre2(tyre){this->name = new char[strlen(name)+1];strcpy(this->name,name);tyre2.print();}Car::~Car(){cout<<"Car destructor:only delete name"<<endl;delete name;}void Car::print(){cout<<"Car :";this->tyre2.print();}int main(){Tyre tyre1("g");Car theCar("lexus",tyre1);theCar.print();return 0;}
編譯運行結果:
D:\workspace\C++\memory_leak\leak2>leakTyre(g)This is g Tyre.Car :This is g Tyre.Car destructor:only delete nameTyre destruct:g
而當包含對象的指標時,就不會像之前那樣自動調用析構了,必須要像以前的規則,new和delete要成對出現:
//#include <iostream>#include <cstring>using namespace std;class Tyre{char* brand;public:Tyre(char* _brand);~Tyre();void print();};Tyre::Tyre(char* _brand){cout<<"Tyre("<<_brand<<")"<<endl;this->brand = new char[strlen(_brand)+1];strcpy(this->brand,_brand);}Tyre::~Tyre(){cout<<"Tyre destruct:"<<brand<<endl;delete brand;}void Tyre::print(){cout<<"This is "<<brand<<" Tyre."<<endl;}class Car{char* name;Tyre* tyre;public:Car(char* name,char* _tyre);~Car();void print();};Car::Car(char* name,char* _tyre){this->name = new char[strlen(name)+1];strcpy(this->name,name);tyre = new Tyre(_tyre);}Car::~Car(){cout<<"Car destructor:only delete name"<<endl;delete name;//delete tyre;//Do not forget.}void Car::print(){cout<<"Car :";tyre->print();}int main(){Car car1("benz","goodyear");car1.print();Car car2("bmw","michelin");car2.print();Car *car3 = new Car("audi","continental");car3->print();delete car3;return 0;}
運行結果如下:
D:\workspace\C++\memory_leak\leak2>leakTyre(goodyear)Car :This is goodyear Tyre.Tyre(michelin)Car :This is michelin Tyre.Tyre(continental)Car :This is continental Tyre.Car destructor:only delete nameCar destructor:only delete nameCar destructor:only delete name
有三個Tyre沒有釋放記憶體,Car::~Car中解開注釋,編譯運行如下:
D:\workspace\C++\memory_leak\leak2>leakTyre(goodyear)Car :This is goodyear Tyre.Tyre(michelin)Car :This is michelin Tyre.Tyre(continental)Car :This is continental Tyre.Car destructor:only delete nameTyre destruct:continentalCar destructor:only delete nameTyre destruct:michelinCar destructor:only delete nameTyre destruct:goodyear
生活中不能缺少經驗,但不要迷信經驗。