#ifndef FATHER_H #define FATHER_H #include"iostream" #include<string> using namespace std; class father{ public: father(std::string name1) : name(name1){ cout << "new " << name << endl; } father(father & f) : name(f.name) { cout << "copy " << f.name << endl; } virtual ~ father(){ cout << "delete " << name << endl; }; //private: std::string name; }; #endif
#include"father.h" #include"iostream" using namespace std; father f(){ father f("lisi"); cout << " hanshu" << endl; return f; } int main() { father &f1 = father("zhangsan"); cout << "hehe" << endl; cout << f1.get() << endl; cout << "------------------------------------" << endl; father & s = f(); cout << " new s" << endl; s.name = "wangwu"; return 0; }
1、可见语句father &f1 = father("zhangsan");是先生成一个临时对象,然后在调用复制构造函数来初始化f1的,而且这个语句结束,临时对象就自动析构了;
2、调用f()函数来初始化s就不一样:先是在f()函数里面构造了一个father对象,即father f("lisi");但是这个对象并没有return给一个临时的函数返回对象,而是直接赋值给s了,调用的是复制构造函数。这很奇怪。因为father f("lisi");是在函数堆栈区的,当函数结束以后,整个堆栈都是pop出来了,为什么还可以用这个堆栈的对象来初始化s呢?据说这个编译器的优化,但具体为什么如此,我还不懂。
注:问题得以解决,其实编译器优化了,father f("lisi");这个对象是函数堆栈对象,是不可能在函数结束以后存在的。只是编译器在ruturn f;的时候,省略了中间的函数返回临时对象的创建,而是直接赋值给mian()函数里面的s引用了。就好像把s作为函数的临时返回对象了一样。
其实可以再做一个实验,仅仅写一个f();的无用语句,你会发现结果也会有new lisi和copy lisi以及两个delete lisi的。说明这个copy lisi的输出是return时候做的,并不是复制语句中做的,只是在直接赋值给一个对象的时候,编译器优化了中间的步骤而已。
3、s是一个引用,这个引用指向的是一个函数返回的临时对象,当这条语句结束的时候,临时对象会自动析构,按道理应该这个引用无效了,但程序显示并非如此,因为调用了复制构造函数来初始化一个father对象,然后使引用s指向它。这也是编译器奇怪的一点?
注:问题得以解决:在C++之父Bjarne Stroustrup的《The C++ Programming Language》的P89的第九行明确指出:“这种保存引用初始式的临时对象将一直存在,直到这个引用的作用域结束”。