c++ - 为什么析构函数什么也不写仍然会delete其成员指针?
PHP中文网
PHP中文网 2017-04-17 13:30:21
0
4
667

class A{
public:
    int _a;
    A(int a) :_a(a){};
};
class B{
    A* _ap;
public:
    B(A& a){
        _ap = &a;
    }
    ~B(){
        //这里并不执行什么,但是_ap仍然被delete了。
    };
};
void main(){
    A* a = new A(1);
    B b(*a);
    delete &b;
    cout << a->_a;
}

是不是不管你析构函数写的什么,都一定会delete掉其所有的成员变量?

PHP中文网
PHP中文网

认证高级PHP讲师

全部回覆(4)
刘奇

是不是不管你析構函數寫的什麼,都一定會delete掉其所有的成員變數?

絕對不可能。

另外,b不是new出來的,把它delete掉的結果是未定義的

以上兩種可以說都是fatal error! ! !
因為前者會導致記憶體洩漏
後者會導致你的程式在某個神奇的時刻以一種神奇的方式crash掉,而且在crash掉之後你基本上很難發現其中隱含的奧秘

迷茫

題主的程式中有幾個問題:

class A{
public:
    int _a;  // 不推荐,变量名不要以下划线开始,但可以以下划线结束,比如 a_
    A(int a) :_a(a){};
};
class B{
    A* _ap;  // 同上
public:
    B(A& a){
        _ap = &a;
    }
    ~B(){
        //这里并不执行什么,_ap 也没有在这里被 delete
    };
};
void main(){
    A* a = new A(1);
    B b(*a);
    delete &b;  // 错误,&b 并不是指向动态分配的内存的指针,对其进行 delete 是未定义的(见文末标准引用)
    cout << a->_a;
    delete a;  // 错误,a 是指向动态分配的内存的指针,需要进行 delete,而题主漏掉了
}

是不是不管你析構函數寫的什麼,都一定會delete掉其所有的成員變數?

不是。你不寫 delete 則析構函數就不會釋放對應指標指向的記憶體。

此外,題主的類別B在設計上也存在問題。如果一個類別的成員是一個指針,那麼需要考慮:

  • B的成員_ap是指向堆疊中的物件還是動態記憶體中的物件?

    • 如果是指向堆疊中的對象,就不需要考慮記憶體的分配和釋放問題;

    • 如果是指向動態記憶體中的對象,則需要考慮記憶體的分配和釋放問題。

  • 如果指向動態內存,那麼指向的內存該由誰管理(分配、釋放)?是類別B還是類別B的使用者(如main函數)?

    • 如果是由類別B管理(這也是通常的做法),那麼對應的建構子和析構函式就會負責動態記憶體的分配和釋放。也就是 C++ 中常說的 Resource Acquisition Is Initialization(RAII)。

    • 如果由類別B的使用者(如main函數)進行管理,那麼使用者(如main函數)就必須在實現的時候仔細考慮資源的分配和釋放問題,否則很容易出錯。

最後,如果不是有特殊需求,不建議使用原始指標(raw pointer),而是使用STL 裡的智慧指標shared_ptrweak_ptrunique_ptr,智慧指標可以自動管理所指向的動態內存,所以不需要考慮什麼時候該釋放內存、會不會多次釋放同一塊內存、會不會一不小心就搞出個野指針等問題。使用方法可以參考 C++ Primer 5e Chapter 12 Dynamic Memory。

C++ 11 Standard § 5.3.5/2
… In the first alternative (delete object), the value of the oper🎜>delete objectdelete), the value of the operand of be a null pointer value, a pointer to a non-array object created by a previous new-expression

, or a object subobject (1.8) representing a base class of spointer to a subobject (1.8) representing a base class of spointer 10object (Clause 10). If not, the behavior is undefined. …
Ty80

只有動態記憶體需要自己手動釋放,其餘的變數在類別變數銷毀時自動釋放。你這裡沒有動態記憶體的分配,所以什麼都不用寫

大家讲道理

兩件事:
1、成員變數如果是指標。那麼程式需要分配的記憶體就是儲存指標所佔用的記憶體(32位元程式是4個位元組)和指標所指向的記憶體。其中指標所佔用的記憶體是有編譯器管理的,而指標指向的記憶體是你自己管理的。
也就是,這個指標所佔用的記憶體(4個位元組)就會自動在析構函式裡自動釋放。但是指標指向的部分記憶體預設析構函數是不會幫你釋放的,因為編譯器也不知道你這個指標指向的是不是你自己分配的內存,也不知道你將來還會不會用這段內存。
2、當程式/行程執行完,程式佔用的所有記憶體都會被作業系統釋放。即使沒有顯示的delete

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板