首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么在这段代码中调用2次析构函数?

在这段代码中调用了两次析构函数的原因可能是由于对象的拷贝或移动操作导致的。

在C++中,当一个对象被拷贝或移动时,会调用相应的拷贝构造函数或移动构造函数来创建新的对象。而当一个对象的生命周期结束时,会调用析构函数来销毁对象并释放资源。

如果在代码中存在对象的拷贝或移动操作,可能会导致多次调用析构函数。以下是一些常见的情况:

  1. 对象的拷贝:当一个对象被赋值给另一个对象时,会调用拷贝构造函数来创建新的对象。在这个过程中,原对象的析构函数会被调用一次,新对象的析构函数也会被调用一次。
  2. 对象的移动:当一个对象被移动到另一个对象时,会调用移动构造函数来创建新的对象。在这个过程中,原对象的析构函数会被调用一次,新对象的析构函数也会被调用一次。
  3. 容器的操作:如果对象被存储在容器中,当容器销毁时,会调用容器中每个对象的析构函数。如果容器进行了拷贝或移动操作,也会导致多次调用析构函数。

需要注意的是,如果在代码中没有明确的拷贝或移动操作,而仍然出现了多次调用析构函数的情况,可能是由于浅拷贝或浅析构导致的。这种情况下,需要检查对象的拷贝构造函数和析构函数的实现,确保正确地管理资源。

总之,在这段代码中调用两次析构函数可能是由于对象的拷贝或移动操作导致的,需要仔细检查代码逻辑和对象的生命周期管理。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

【C++】构造函数与析构函数概念简介 ( 构造函数和析构函数引入 | 构造函数定义与调用 | 析构函数定义与调用 | 代码示例 )

" 构造函数 " 是 C++ 类中的一种特殊的 " 成员函数 " , 该函数不需要用户手动调用 , 而是在 C++ 类 实例对象 创建时 , 自动执行的 ; " 析构函数 " 是 构造函数 的 对应相反的函数...s1, s2; 在代码中声明了 2 个 Student 变量 , 构造函数调用了 2 次 ; 代码示例 : #include "iostream" using namespace std; class...; 析构函数返回值 : 析构函数 没有返回值 ; 2、析构函数调用 析构函数调用 : 自动调用 : C++ 编译器会 在销毁 C++ 类实例对象时 , 自动调用类的 析构函数 ; 3、代码示例 - 析构函数定义与调用...s1, s2; , main 函数执行结束 , 也就是程序终止时 , 会自动调用 ~Student() 析构函数 , 因此在程序退出前 , 会自动为 2 个 Student 对象调用析构函数 ; 代码示例...析构函数 析构函数 在栈内存中定义了 Student s1, s2; 对象变量 , 栈内存的特点是 后进先出 , 创建时 , 第一个构造函数调用的是 s1 的构造函数 , 第二个构造函数调用的是 s2

35520

Java中的“析构函数”——finalize() 对象消亡时调用

这些特性之一就是析构函数。取代使用析构函数,Java 支持finalize() 方法。   在本文中,我们将描述 finalize() 与 C++ 析构函数的区别。...因为这一双重支持,C++ 也提供了自动构造和析构,这导致了对构造函数和析构函数的调用,(对于堆对象)就是内存的分配和释放。   在 Java 中,所有对象都驻留在堆内存,因此局部对象就不存在。...如果finalize() 不是析构函数,JVM 不一定会调用它,你可能会疑惑它是否在任何情况下都有好处。事实上,在 Java 1.0 中它并没有太多的优点。   ...在我们讨论了finalize() 与 C++ 的析构函数的不同点后,对这个结论不会惊讶,因为为某个类定制的清除代码另一个类不一定会需要。   ...值得C++程序员注意的是,finalize()方法并不能等同与析构函数。Java中是没有析构函数的。C++的析构函数是在对象消亡时运行的。

3.3K10
  • C++不要在构造函数和析构函数中调用虚函数

    但是为什么在构造函数中调用虚函数,实际上没有发生动态联编呢? 1. 不要在构造函数中调用虚函数的原因 第一个原因,在概念上,构造函数的工作是为对象进行初始化。...2.不要在析构函数中调用虚函数的原因 同样的,在析构函数中调用虚函数,函数的入口地址也是在编译时静态决定的。也就是说,实现的是实调用而非虚调用。 考察如下例子。...B的对象b退出作用域时,会先调用类B的析构函数,然后调用类A的析构函数,在析构函数~A()中,调用了虚函数show()。...从概念上说,析构函数是用来销毁一个对象的,在销毁一个对象时,先调用该对象所属类的析构函数,然后再调用其基类的析构函数,所以,在调用基类的析构函数时,派生类对象的“善后”工作已经完成了,这个时候再调用在派生类中定义的函数版本已经没有意义了...因此,一般情况下,应该避免在构造函数和析构函数中调用虚函数,如果一定要这样做,程序猿必须清楚,这是对虚函数的调用其实是实调用。

    3.8K30

    反常识:为什么虚函数在构造和析构时并不“虚”?

    三个函数 本题从字面中可以看到涉及到三个函数,分别是: 构造函数:构造函数是用来初始化对象的,它会在对象创建时被调用。 析构函数:析构函数是用于清理对象的,它会在对象销毁时被调用。...父类析构函数中调用虚函数,执行的是父类中的函数还是子类中重写的虚函数呢? 子类构造函数中调用虚函数,执行的是父类中的函数还是子类中重写的虚函数呢?...子类析构函数中调用虚函数,执行的是父类中的函数还是子类中重写的虚函数呢? 只是,子类构造函数、子类析构函数中调用的虚函数如同子类自身的其他普通函数一样,调用的必定是子类中重写的函数。...所以并不符合多态的预期,那也就没有必要使用虚函数了,也就是说虚函数在构造函数和析构函数中是“失效”的,不建议在构造函数和析构函数中调用虚函数。...} 输出结果: Base::cleanup() 建总结议 如上从原理、实验都验证了,构造函数、析构函数中虽然可以调用虚函数,但是虚函数“失效”了,所以并不符合多态的预期,没有必要使用虚函数,所以不建议在构造函数和析构函数中调用虚函数

    7810

    构造函数以及析构函数在PHP中需要注意的地方

    构造函数以及析构函数在PHP中需要注意的地方 基本上所有的编程语言在类中都会有构造函数和析构函数的概念。...C:析构函数被调用,$c // A:析构函数被调用,$b // B:析构函数被调用,$b // A:析构函数被调用,$a 上面的代码是不是有一些内容和我们的预期不太一样?...,则默认调用父类的 析构函数如果没显式地将变量置为NULL或者使用unset()的话,会在脚本执行完成后进行调用,调用顺序在测试代码中是类似于栈的形式先进后出(C->B->A,C先被析构),但在服务器环境中则不一定...,也就是说顺序不一定固定 析构函数的引用问题 当对象中包含自身相互的引用时,想要通过设置为NULL或者unset()来调用析构函数可能会出现问题。...关于单例模式为什么要让外部无法实例化的问题,我们可以看看之前的设计模式系统文章中的单例模式。

    1.7K20

    C++核心准则C.82:不要在构造函数或析构函数中调用虚函数

    C.82: Don't call virtual functions in constructors and destructors C.82:不要在构造函数或析构函数中调用虚函数 Reason...到目前为止,被调用的函数应该只属于构造对象本身,而不是可能存在于派生类中的某个覆盖函数。那样做非常难理解。...最坏的情况,在构造函数或者析构函数中直接或间接调用一个没有实现的纯虚函数会导致没有定义的行为。...从构造函数和析构函数中调用虚函数并不是本身有什么错误。这种调用的语义是安全的。然而,经验表明这样的调用很少是必须的,很容易扰乱维护者,如果被新手使用会成为错误源。...提示来自构造函数或析构函数的虚函数调用。

    79750

    C++11 在析构函数中执行lambda表达式(std::function)捕获this指针的陷阱

    一个简单的例子 下面是一段很简单的lambda测试代码。总体的功能就是让对象在析构时执行指定的std::function函数对象。...test_lambda_base 类的功能很简单,就是在析构函数中执行构造函数传入的一个std::function对象。...: 析构函数体->清除成员变量->析构基类部分(从右到左)->析构虚基类部分 所以上面代码中在test_lambda_base的析构函数中执行子类test_lambda的成员变量fun时,fun作为一个...为了证实这个判断,打开头文件#include 找到function的析构函数,如下图在析构函数上设置一个调试断点,再运行程序到断点处。 看下图中的”调用堆栈”窗口。...解决问题 解决这个问题的办法很多种, 总的原则就是:如果要在析构函数中调用lambda表达,就要避免lambda使用类成员变量, 对于这个例子,最简单的办法就是修改test_lambda构造函数

    1.7K10

    【C++】运算符重载案例 - 字符串类 ① ( Visual Studio 中创建 String 类 | 构造函数与析构函数 | 完整代码示例 )

    , delete 会自动调用析构函数 ; m_p = new char[m_len + 1]; 最后 , 拷贝空字符串到 m_p 指向的内存中 ; // 拷贝空字符串到 m_p 指向的内存中 strcpy...strcpy(m_p, p); } cout 调用有参构造函数" << endl; }; 4、拷贝构造函数 在 拷贝构造函数中 , 使用 String 对象初始化 对象值 ; 首先 ,...strcpy(this->m_p, s.m_p); cout 调用拷贝构造函数" << endl; } 6、析构函数 析构函数中 , 使用 delete 释放之前使用 new 分配的内存...; 代码示例 : // 析构函数 String::~String() { if (this->m_p !...strcpy(this->m_p, s.m_p); cout 调用拷贝构造函数" << endl; } // 析构函数 String::~String() { if (this->m_p

    25220

    c++类和继承面试点25连问

    ,再调用派生类的构造函数; 派生类对象销毁时,先调用派生类的析构函数,再调用基类的析构函数。...= nullptr ) { delete a; } return 0; } 这段代码执行后输出如下: A() B() ~A() 构造的时候是正常的,但是析构的时候只调用了基类的析构函数...,能确保派生类的析构函数会被调用。...因为销毁的时候直接销毁的基类指针,此时编译器只知道调用基类析构,并不会主动去调用派生类的析构函数,所以基类析构函数需为虚析构函数,这样运行时程序才会去调用派生类的析构函数,其实这就相当于析构函数的多态,...基于多态的作用,这个指向派生类的基类指针会先调用派生类的析构函数,然后再调用基类的析构函数。

    99410

    C++天使的灵动心跳代码:类和对象(中上)

    而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。...main 中根本没有直接创建 Time 类的对象,为什么最后会调用 Time 类的析构函数?...但是:main 函数中不能直接调用 Time 类的析构函数,实际要释放的是 Date 类对象,所以编译器会调用 Date 类的析构函数,而Date 没有显式提供,则编译器会给 Date 类生成一个默认的析构函数...类生成的默认析构函数,创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数 3.2 显式调用析构函数 当使用 malloc 在预先分配好的内存空间中创建对象时,就需要显式调用析构函数来进行对象销毁...) { Array arr(5); return 0; } 这段代码自动调用构造函数和析构函数实现了空间创建和销毁,避免忘记释放或开辟空间 值得注意的是: 一般情况下有动态资源申请,

    4500

    Cpp虚函数相关知识点

    人要工作,人派生出多个子类后,一个作家工作就是写文章,一个程序员工作却是写代码。工作的执行者不同,工作的内容也不同。 在类中成员函数前面加一个virtual,这个函数就变成了虚函数。...可以看这一篇文章探索C++虚函数在g++中的实现,讲的很详细。 析构函数为什么是虚函数 明白了虚函数的特点,这个问题就不难了。...当基类指针指向子类对象的时候,在对象使用完毕需要释放时,肯定需要调用子类对象的析构函数呀,所以这种情况下析构函数也得是虚函数。...也可以看这段话: 基类指针可以指向派生类的对象(多态性),如果删除该指针delete []p; 就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用 基类的析构函数,这样整个派生类的对象完全被释放...如果析构函数不被声明成虚函数,则编译器实施静态绑定, 在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数, 这样就会造成派生类对象析构不完全。所以,将析构函数 声明为虚函数是十分必要的。

    39920

    类和对象(中篇)

    而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。 特性 析构函数是特殊的成员函数,其特征如下: 析构函数名是在类名前加上字符 ~。 无参数无返回值类型。...() // 在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的析构函数?...但是: //main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date //类的析构函数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数...,目的是在其内部 //调用Time类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁 //main函数中并没有直接调用Time类析构函数,而是显式调用编译器为Date类生成的默认析构函数...// 注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数 如果类中没有申请资源时,析构函数可以不写(自动回收),直接使用编译器生成的默认析构函数,比如Date类;有资源申请时

    8810

    构造函数和析构函数可以是虚函数吗,在里面能调用虚函数吗

    构造函数作为虚函数让人觉得是你的构造函数可能是动态的,那我觉得这可能是另一个设计模式,对象固定,构建方法动态来达到多态的目的,后面这段是我自己的看法 析构函数作为虚函数?...那么析构函数作为虚函数在什么场景下会用到呢,看看下面这段代码 #include using namespace std; class Father { public: Father...这时候如果是基类指针指向子类对象,那么删除指针,只会调用基类的析构函数,因为这时候对象类型是基类对象,析构函数没有动态绑定,只会调用当前对象类型的析构。...那在构造函数里能调用虚函数吗 这个问题之前腾讯后端一面出现过,我当时有点蒙 首先编译器是允许你这么做的,但是在构造函数里调用虚函数,可能达不到你想要的效果,我们看看下面的代码 class Father...//Father f 代码运行后,构造函数只调用了父类的虚函数,我们本来想要调用子类的虚函数。

    1.6K50

    多态

    所以析构函数的重写只需要在基类上加上virtual就可以构成重写。 为什么对析构函数进行重写呢?...当我们写成虚函数virtual ~teacher(),构成多态之后,就可以全部正常的对子类释放(调用子类的析构函数时,先析构子类,再析构父类): C++11中的 override和final final...要想观察这个调用print是什么方式的,需要看一下汇编代码。 单继承虚函数表 上面那个代码就是单继承,但是上面那个代码中,派生类没有写自己的虚函数,只是不继承的虚函数重写了。...静态的成员不能是虚函数,静态成员没有*this指针,静态函数只能用类域的方式调用,而虚函数的调用需要在虚函数表在中调用。 构造函数和拷贝构造函数不能是虚函数。...赋值运算符的重载是可以是虚函数的 析构函数可以是虚函数,虽然析构函数的函数名不一样,但是在编译器看来,都被处理为destructor,上文有解释为什么要把析构函数写成虚函数。

    26020

    C++新旅程:类的构造函数和析构函数

    Date d1, d2,d3;//创建对象d1.SetDate();d1.Show();d2.SetDate();d2.Show();d3.SetDate();d3.Show();return 0;} 上面这段代码中的日期类对象的初始化赋值我们调用了类的成员函数...(2015, 1, 1); // 调用带参的构造函数d1.Show();d2.Show();//Date d3();//d3.Show();return 0;} 在上面这段代码中无参构造函数是默认生成的构造函数...自定义类型成员调用默认构造函数 内置类型有缺省值用缺省值,没有缺省值看编译器是否处理 (3)成员变量在类中声明的次序才是初始化列表中成员变量初始化的顺序 注:初始化列表中成员变量初始化的顺序,与成员变量在初始化列表中的先后位置无关...而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。3.2特性(1) 析构函数名是在类名前加上字符 ~。(2)无参数、无返回值类型。(3) 一个类只能有一个析构函数。...当函数被首次调用建立对象时,调用其构造函数,当主函数执行完毕前调用其析构函数。3、全局对象全局对象在程序一开始时,其构造函数就会被执行(这通常比程序进入点更早)。

    5610

    跟面试官聊.NET垃圾收集,直刺面试官G点

    既然有了垃圾收集器,为什么还要Dispose方法和析构函数? 因为CLR的缘故,GC只能释放托管资源,不能释放非托管资源(数据库链接、文件流等) 那么该如何释放非托管资源呢?...那么就要用到析构函数了。 析构函数是个很奇怪的函数,调用者无法调用对象的析构函数,析构函数是由GC调用的。...你无法预测析构函数何时会被调用,所以尽量不要在这里操作可能被回收的托管资源,析构函数只用来释放非托管资源 GC释放包含析构函数的对象,比较麻烦(需要干两次才能干掉她), CLR会先让析构函数执行,再收集它占用的内存...这个时候就用到了弱引用,来看看下面这段代码: var bss = new BsCtl(BrowserContainer); var vbss = new...//如果没有进行垃圾收集OK不会为NULL if (ok == null) { //如果已经进行了垃圾收集,就会执行这段代码

    78060

    生成一个C++对象的成本

    举个例子吧,就像什么析构函数总喜欢写成virtual?这个例子应该容易说明virtual的玩法。...就是说,如果不用virtual函数,是没有执行期绑定一说的,比如pObj1这个指针,其实它是Child对象,但是在释放时,~Child()方法并没有被调用,仅调用了~Father方法。为什么呢?...因为没有用virtual,就是编译期绑定,当你在编译时gcc/g++只知道pObj1是个Father对象,所以在delete时就去调用Father的析构了。...而如果定义成virtual ~Father时,结果就是一定会析构Child,这就是为什么析构函数都要用virtual,因为没人知道会不会有子类继承,否则一旦继承,发生这样的事,析构函数里万一释放了些资源...即使一个Child对象在编译时被赋为Father类型,但是实际调用时,virtual方法会被单独的拎出来,在vtbl中指向实际的实现,所以,该对象在delete时会调用Child的析构函数,而如果你像上面例子那样

    46830
    领券