Date与Employee类构造/析构函数调用次数差异及执行序列问询
Hey,作为C++新手遇到这种构造析构次数不一致的问题太正常了,咱们一点点拆解清楚:
先看你的代码
Date.h
#include<iostream> #include<cstdlib> #include<cstring> using namespace std; class Date{ private: int day; int month; int year; public: Date(int d = 1, int m = 1, int y = 1900): day(d), month(m), year(y) { cout << "date constructor is called" << endl; } void print() const { cout << day << ":" << month << ":" << year << endl; } ~Date(){ cout << "date destructor is called" << endl; } };
Employee.h
#include"Date.h" class Employee{ private: char *fname; char *lname; Date dob; // has-a关系 Date hiredate; // has-a关系 public: Employee(char *f, char *l, Date bd, Date hd){ cout << "employee constructor is called" << endl; int lengthf; lengthf = strlen(f); fname = new char[lengthf+1]; strcpy(fname, f); int lengthl; lengthl = strlen(l); lname = new char[lengthl +1]; strcpy(lname, l); } ~Employee(){ delete [] fname; delete [] lname; cout << "employee destructor is called" << endl; } };
主函数
#include"Employee.h" int main(){ Date db(07, 11, 1991); Date dh; dh.print(); Employee e("Dan", "Lee", db, dh); db.print(); system("pause"); return 0; }
问题1:为啥Date构造4次、析构6次?
核心原因就是按值传递参数会生成临时拷贝对象,但这里有个关键细节:你的Date类没有显式定义拷贝构造函数,编译器会自动生成一个默认拷贝构造——但这个默认拷贝构造不会执行你写的那个带cout输出的构造函数,所以这两次拷贝的构造不会被你统计到。
而临时拷贝对象销毁时,会调用你显式写的析构函数,所以就多了2次析构,最终构造4次、析构6次。
问题2:完整的构造&析构调用序列
咱们按代码执行的顺序一步步捋,把每个节点的调用都列出来:
构造函数调用(带输出的4次):
- 执行
Date db(07, 11, 1991);→ 调用带参构造,输出date constructor is called(第1次) - 执行
Date dh;→ 调用默认构造,输出date constructor is called(第2次) - 创建
Employee e时,C++会先初始化类的成员变量(在构造函数体执行前):- 初始化
dob→ 调用Date默认构造,输出date constructor is called(第3次) - 初始化
hiredate→ 调用Date默认构造,输出date constructor is called(第4次)
- 初始化
- 进入Employee构造函数体,输出
employee constructor is called注意:这里传递的参数
bd和hd是按值传递,编译器用默认拷贝构造生成了两个临时Date对象,但因为默认拷贝构造没有输出,所以你看不到这两次构造的打印。
析构函数调用(共6次,顺序是栈式的“后进先出”):
- Employee构造函数执行完毕后,传递参数时生成的两个临时Date对象(
bd和hd的拷贝)被销毁 → 调用2次Date析构,输出date destructor is called(第1、2次) system("pause")执行完成后,main函数开始销毁局部变量:- 先销毁
Employee e:- 执行Employee析构函数体,输出
employee destructor is called - 销毁Employee的成员变量:先销毁
hiredate→ 调用Date析构(第3次),再销毁dob→ 调用Date析构(第4次)
- 执行Employee析构函数体,输出
- 接着销毁
dh→ 调用Date析构(第5次) - 最后销毁
db→ 调用Date析构(第6次)
- 先销毁
问题3:按值传递vs按引用传递的差异
按值传递时析构次数增多的原因:
按值传递参数时,C++必须创建一个参数的独立拷贝——这个拷贝是全新的对象,在函数/构造函数执行完成后,这个临时对象就会被立即销毁,所以会多一次析构调用。你的代码里有两个Date类型的按值参数,就多了2次析构,导致析构次数比构造多。
按引用传递时次数一致的原理:
如果把Employee构造函数改成按引用传递(建议加const避免意外修改):
Employee(char *f, char *l, const Date& bd, const Date& hd)
这时候,bd和hd只是原对象(db和dh)的“别名”,不会创建任何新的Date对象。所以构造次数还是4次(db、dh、dob、hiredate),析构次数也是这4个对象的析构,Date的构造和析构次数就完全一致了。
内容的提问来源于stack exchange,提问作者Rizwan Muzaffar
相关产品推荐
相关产品推荐

