類的解構函式自動呼叫

海_纳百川發表於2024-11-30

類的解構函式會自動呼叫。解構函式是在物件的生命週期結束時由系統自動呼叫的特殊成員函式,主要用於釋放物件佔用的資源,執行清理工作。

具體情況

  1. 自動呼叫的時機

    • 區域性物件:當物件離開其作用域時,解構函式會自動呼叫。

      #include <iostream>
      class MyClass {
      public:
          ~MyClass() {
              std::cout << "Destructor called!" << std::endl;
          }
      };
      
      int main() {
          MyClass obj;  // 建構函式呼叫
          // 離開作用域,obj 被銷燬,呼叫解構函式
          return 0;
      }
      

      輸出:

      Destructor called!
      
    • 動態分配的物件:當使用 deletedelete[] 釋放動態分配的物件時,解構函式會被呼叫。

      MyClass* obj = new MyClass;
      delete obj;  // 呼叫解構函式
      
    • 容器管理的物件:當容器銷燬時,解構函式會被呼叫以清理容器中儲存的物件。

      std::vector<MyClass> vec(3);  // 構造三個物件
      // 離開作用域時,解構函式會依次呼叫
      
  2. 不會自動呼叫的情況

    • 如果物件是透過動態分配建立的(使用 new),但沒有顯式使用 delete,解構函式不會自動呼叫,造成記憶體洩漏
    • 使用 mallocfree 分配和釋放記憶體時,不會呼叫建構函式或解構函式。
  3. 虛解構函式的注意事項

    • 如果基類的解構函式沒有宣告為 virtual,透過基類指標或引用刪除派生類物件時,可能不會呼叫派生類的解構函式,導致資源未正確釋放。

      class Base {
      public:
          ~Base() { std::cout << "Base Destructor\n"; }
      };
      
      class Derived : public Base {
      public:
          ~Derived() { std::cout << "Derived Destructor\n"; }
      };
      
      int main() {
          Base* obj = new Derived();
          delete obj;  // 只呼叫 Base 的解構函式
          return 0;
      }
      

      輸出:

      Base Destructor
      

      修正:

      class Base {
      public:
          virtual ~Base() { std::cout << "Base Destructor\n"; }
      };
      
      class Derived : public Base {
      public:
          ~Derived() { std::cout << "Derived Destructor\n"; }
      };
      
      int main() {
          Base* obj = new Derived();
          delete obj;  // 同時呼叫 Derived 和 Base 的解構函式
          return 0;
      }
      

      輸出:

      Derived Destructor
      Base Destructor
      

總結

解構函式的呼叫是由編譯器或執行時自動管理的,在物件生命週期結束時自動觸發,使用者通常無需手動呼叫。不過要注意在動態分配和繼承場景下正確管理物件和宣告虛解構函式,避免資源洩漏或不完全釋放的問題。


當你使用 mallocfree 進行記憶體分配和釋放時,確實不會呼叫建構函式或解構函式。這是因為 mallocfree 僅僅是對記憶體的分配和釋放操作,它們不涉及物件的生命週期管理,因此不會觸發構造和析構的呼叫。具體原因和情況如下:

1. mallocfree 的工作原理

  • malloc 是 C 語言中的記憶體分配函式,它從堆中分配指定大小的記憶體塊,並返回指向該記憶體的指標。它只是簡單地為指定大小的記憶體塊分配空間,並不會對記憶體中的資料進行任何初始化。它只負責記憶體的分配,不會呼叫建構函式。

  • free 是 C 語言中的記憶體釋放函式,它將透過 malloc 分配的記憶體塊標記為可重用的,並將該記憶體歸還給系統。free 只是釋放記憶體,不會呼叫解構函式。

2. 建構函式和解構函式的呼叫

在 C++ 中,建構函式和解構函式是用於初始化和銷燬物件的特殊成員函式。它們通常由 newdelete 運算子負責呼叫,而不是 mallocfree

  • newdelete 會在分配和釋放記憶體時自動呼叫物件的構造和解構函式:

    • 當你使用 new 來分配記憶體時,C++ 會先分配足夠的記憶體空間,然後在這塊記憶體上呼叫類的建構函式來初始化物件。
    • 當你使用 delete 釋放記憶體時,C++ 會先呼叫類的解構函式來清理物件資源,然後再釋放記憶體。
  • mallocfree 不涉及物件的生命週期管理,它們只負責原始記憶體的分配和釋放,不會呼叫建構函式和解構函式。

3. 程式碼示例

使用 mallocfree (沒有呼叫建構函式/解構函式)

#include <iostream>
#include <cstdlib>  // malloc, free

class MyClass {
public:
    MyClass() {
        std::cout << "Constructor called" << std::endl;
    }
    ~MyClass() {
        std::cout << "Destructor called" << std::endl;
    }
};

int main() {
    // 使用 malloc 分配記憶體
    MyClass* ptr = (MyClass*)malloc(sizeof(MyClass));

    // 注意:此時並未呼叫建構函式

    free(ptr);  // 釋放記憶體
    // 注意:此時並未呼叫解構函式
}

輸出:

(沒有任何輸出)

在上面的程式碼中,malloc 只分配了記憶體,並沒有呼叫 MyClass 的建構函式,free 也沒有呼叫解構函式。

使用 newdelete (會呼叫建構函式/解構函式)

#include <iostream>

class MyClass {
public:
    MyClass() {
        std::cout << "Constructor called" << std::endl;
    }
    ~MyClass() {
        std::cout << "Destructor called" << std::endl;
    }
};

int main() {
    // 使用 new 分配記憶體並呼叫建構函式
    MyClass* ptr = new MyClass;

    // 使用 delete 釋放記憶體並呼叫解構函式
    delete ptr;
}

輸出:

Constructor called
Destructor called

在這個例子中,new 分配了記憶體並自動呼叫了建構函式,而 delete 釋放記憶體時,自動呼叫了解構函式。

4. 為什麼 mallocfree 不呼叫構造和解構函式?

mallocfree 是 C 標準庫函式,它們是為 C 語言設計的,不關心 C++ 類的構造和析構過程。C++ 引入了 物件 的概念,要求在記憶體分配時不僅要分配記憶體空間,還要初始化物件的狀態,因此引入了 newdelete 運算子,這兩個運算子自動處理構造和析構。

5. 結論

  • 使用 mallocfree 分配和釋放記憶體時,不會呼叫建構函式和解構函式,它們只是分配和釋放原始記憶體空間。
  • 如果你需要在 C++ 中管理物件的生命週期,應該使用 newdelete,因為它們會自動呼叫構造和解構函式。
  • mallocfree 更適合用於 C 程式設計中,或者用於低階記憶體操作時,不涉及物件的生命週期管理。

相關文章