首頁  >  問答  >  主體

c++ - 为什么析构函数什么也不写仍然会delete其成员指针?


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中文网2765 天前629

全部回覆(4)我來回復

  • 怪我咯

    怪我咯2017-04-17 13:32:21

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

    絕對不可能。

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

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

    回覆
    0
  • 迷茫

    迷茫2017-04-17 13:32:21

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

    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. …
    <🎜>

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 13:32:21

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

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-17 13:32:21

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

    回覆
    0
  • 取消回覆