C++析构函数调用次数异常咨询:为何出现3次析构调用?
问题分析:额外析构调用的真相
你的代码中总共存在3个A类型对象,对应3次析构调用,输出3个0,加上两次拷贝构造的1,最终输出11000是完全正常的,并没有“额外”的析构。你误以为析构来自那一行,是因为对析构时机的误解,加上代码中的一个小错误导致的混淆:
1. 对象数量与析构时机拆解
- 栈对象
a:在main函数开始时构造,main执行完毕返回时自动析构,输出第一个0。 - 堆对象
*b:通过new A(a)构造,触发拷贝构造函数输出1,在delete b时析构,输出第二个0。 - 堆对象
*c:通过new A(*b)构造,触发拷贝构造函数输出第二个1,在delete c时析构,输出第三个0。
你看到的“那一行输出110”,实际是那一行执行时输出两个1,紧接着main函数返回时栈对象a析构输出0,你误以为这个0是那一行触发的。
2. 拷贝构造函数的错误
你的拷贝构造函数中使用A::v = a.v;是错误的:
A(A &a) {A::v = a.v; cout << "1";}
v是类的非静态成员,不能通过类名::成员名的方式直接访问(这种写法仅适用于静态成员)。正确的写法应该是直接赋值给当前对象的v:
A(A &a) {v = a.v; cout << "1";} // 或者显式使用this指针:this->v = a.v;
这个错误属于未定义行为,编译器可能生成异常代码,加重了你对析构来源的误解,但即使修正这个错误,最终输出依然是11000,因为3个对象的析构是必然的。
3. 验证方式
你可以在构造函数和析构函数中添加对象地址的输出,清晰看到每个对象的生命周期:
#include <iostream> using namespace std; class A { public: float v; A() {v = 1.0; cout << "[构造] 栈对象: " << this << endl;} A(A &a) {v = a.v; cout << "[拷贝构造] 堆对象: " << this << " 来自: " << &a << endl;} ~A() { cout << "[析构] 对象: " << this << endl;} float set(float v){ this->v = v; return v; } float get(float v){ return this->v; } }; int main(){ cout << "=== 创建对象 ===" << endl; A a, *b = new A(a), *c = new A(*b); cout << "=== 执行函数调用 ===" << endl; c->get(b->get(a.set(1.0))); cout << "=== 删除堆对象b ===" << endl; delete b; cout << "=== 删除堆对象c ===" << endl; delete c; cout << "=== main函数结束 ===" << endl; return 0; }
运行后你会清晰看到:
- 栈对象
a的析构发生在main函数结束时,而非对象创建的那一行。 - 两次
delete分别对应两个堆对象的析构。
内容的提问来源于stack exchange,提问作者Scott Field
相关产品推荐
相关产品推荐

