首页 > 其他分享 >类的析构函数自动调用

类的析构函数自动调用

时间:2024-11-30 18:43:26浏览次数:7  
标签:malloc 调用 函数 free 内存 析构

类的析构函数会自动调用。析构函数是在对象的生命周期结束时由系统自动调用的特殊成员函数,主要用于释放对象占用的资源,执行清理工作。

具体情况

  1. 自动调用的时机

    • 局部对象:当对象离开其作用域时,析构函数会自动调用。

      #include <iostream>
      class MyClass {
      public:
          ~MyClass() {
              std::cout << "Destructor called!" << std::endl;
          }
      };
      
      int main() {
          MyClass obj;  // 构造函数调用
          // 离开作用域,obj 被销毁,调用析构函数
          return 0;
      }
      

      输出:

      Destructor called!
      
    • 动态分配的对象:当使用 delete 或 delete[] 释放动态分配的对象时,析构函数会被调用。

      MyClass* obj = new MyClass;
      delete obj;  // 调用析构函数
      
    • 容器管理的对象:当容器销毁时,析构函数会被调用以清理容器中存储的对象。

      std::vector<MyClass> vec(3);  // 构造三个对象
      // 离开作用域时,析构函数会依次调用
      
  2. 不会自动调用的情况

    • 如果对象是通过动态分配创建的(使用 new),但没有显式使用 delete,析构函数不会自动调用,造成内存泄漏
    • 使用 malloc 和 free 分配和释放内存时,不会调用构造函数或析构函数。
  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
      

总结

析构函数的调用是由编译器或运行时自动管理的,在对象生命周期结束时自动触发,用户通常无需手动调用。不过要注意在动态分配和继承场景下正确管理对象和声明虚析构函数,避免资源泄漏或不完全释放的问题。


当你使用 malloc 和 free 进行内存分配和释放时,确实不会调用构造函数或析构函数。这是因为 malloc 和 free 仅仅是对内存的分配和释放操作,它们不涉及对象的生命周期管理,因此不会触发构造和析构的调用。具体原因和情况如下:

1. malloc 和 free 的工作原理

  • malloc 是 C 语言中的内存分配函数,它从堆中分配指定大小的内存块,并返回指向该内存的指针。它只是简单地为指定大小的内存块分配空间,并不会对内存中的数据进行任何初始化。它只负责内存的分配,不会调用构造函数。

  • free 是 C 语言中的内存释放函数,它将通过 malloc 分配的内存块标记为可重用的,并将该内存归还给系统。free 只是释放内存,不会调用析构函数。

2. 构造函数和析构函数的调用

在 C++ 中,构造函数和析构函数是用于初始化和销毁对象的特殊成员函数。它们通常由 new 和 delete 运算符负责调用,而不是 malloc 和 free

  • new 和 delete 会在分配和释放内存时自动调用对象的构造和析构函数:

    • 当你使用 new 来分配内存时,C++ 会先分配足够的内存空间,然后在这块内存上调用类的构造函数来初始化对象。
    • 当你使用 delete 释放内存时,C++ 会先调用类的析构函数来清理对象资源,然后再释放内存。
  • malloc 和 free 不涉及对象的生命周期管理,它们只负责原始内存的分配和释放,不会调用构造函数和析构函数。

3. 代码示例

使用 malloc 和 free (没有调用构造函数/析构函数)

#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 也没有调用析构函数。

使用 new 和 delete (会调用构造函数/析构函数)

#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. 为什么 malloc 和 free 不调用构造和析构函数?

malloc 和 free 是 C 标准库函数,它们是为 C 语言设计的,不关心 C++ 类的构造和析构过程。C++ 引入了 对象 的概念,要求在内存分配时不仅要分配内存空间,还要初始化对象的状态,因此引入了 new 和 delete 运算符,这两个运算符自动处理构造和析构。

5. 结论

  • 使用 malloc 和 free 分配和释放内存时,不会调用构造函数和析构函数,它们只是分配和释放原始内存空间。
  • 如果你需要在 C++ 中管理对象的生命周期,应该使用 new 和 delete,因为它们会自动调用构造和析构函数。
  • malloc 和 free 更适合用于 C 编程中,或者用于低级内存操作时,不涉及对象的生命周期管理。

标签:malloc,调用,函数,free,内存,析构
From: https://www.cnblogs.com/chentiao/p/18578747

相关文章

  • 使用函数输出一个整数的逆序数
    Description本题要求实现一个求整数的逆序数的简单函数。(注意:逆序后去掉前导0)函数接口定义:intreverse(intnumber);其中函数reverse须返回用户传入的整型number的逆序数。Input一行一个整数n。Output一个整数表示答案。SampleInput1 -12340SampleOutput1-4......
  • 使用函数验证哥德巴赫猜想
    Description本题要求实现一个判断素数的简单函数,并利用该函数验证哥德巴赫猜想:任何一个不小于6的偶数均可表示为两个奇素数之和。最后给定两个整数m和n,按顺序输出满足条件的数,并按一定形式输出。(素数就是只能被1和自身整除的正整数。注意:1不是素数,2是素数。)函数接口定义:int......
  • 基于查表法实现 Softmax 函数
    1简介在深度学习领域,Softmax函数是一种广泛应用的激活函数,尤其在多分类问题中表现突出。它能够将原始的得分转换为概率分布,使每个类别的概率值都处于0到1之间且总和为1。Softmax内含有大量的指数运算,这使得它在嵌入式端(例如RV1106)上计算较慢。针对量化模型,模型的输出一......
  • C#里怎么样使用Array.BinarySearch函数?
    C#里怎么样使用Array.BinarySearch函数?因为二分算法如此重要,所以要多加练习。但是它的返回值,也有三种状态,导致很多人使用它的时候,也感觉到迷惑的。在这里的例子演示了三种返回值的使用: /**C#ProgramtoSearchanelementwithArrayIndices*/usingSystem;c......
  • opencv调用摄像头(卡尔曼滤波)
    importcv2importnumpyasnpimportonnxruntimeimportxlsxwriterimportos#coco80类别CLASSES=['card']classYOLOV5():def__init__(self,onnxpath):self.onnx_session=onnxruntime.InferenceSession(onnxpath)self.input......
  • opencv调用摄像头并输出位置信息
    importcv2importnumpyasnpimportonnxruntimeimportxlsxwriterimportos#coco80类别CLASSES=['card']classYOLOV5():def__init__(self,onnxpath):self.onnx_session=onnxruntime.InferenceSession(onnxpath)self.input......
  • 基于 Eigen 实现 Softmax 函数
    1简介Eigen是一个高效、易于使用的C++模板库,广泛应用于线性代数计算。本文将介绍如何使用Eigen实现Softmax函数,这是一种常用的归一化函数,在深度学习中具有重要应用。通过Eigen的矩阵运算和向量运算,我们可以快速、准确地实现Softmax函数,提高深度学习模型的训练和推理......
  • 使用 Eigen 实现 CosineSimilarity 函数
    1简介Eigen是一个高效、易于使用的C++模板库,广泛应用于线性代数计算。本文将介绍如何使用Eigen实现CosineSimilarity函数,这是一种常用的相似度度量方法,可以用于衡量两个向量之间的相似程度。通过Eigen的矩阵运算和向量运算,我们可以快速、准确地实现CosineSimilarity函......
  • 《SVM 中核函数的选择:开启精准分类与回归的关键钥匙》
    在支持向量机(SVM)的世界里,核函数就像是一个神奇的魔法师,它能够将低维空间的数据映射到高维空间,从而让原本在低维空间中线性不可分的数据在高维空间中变得线性可分。然而,如何选择合适的核函数却是一个充满技巧和考量的过程,这直接关系到SVM模型的性能和准确性。一、理解核函数......
  • scanf函数、getchar函数、gets函数等函数的误区(回车输出问题)
     目录一、运行原理二、从代码角度观察三、总结四、那怎么解决这种情况呢(1)、方法一(2)、方法二 五、补充一、运行原理scanf函数、getchar函数、gets函数等这类函数是这样的运行的:可以看出来,scanf函数并不是键盘按什么,就读取什么,换种说法是键盘输入和函数读取不......