理论部分
有关临时对象的生命周期有三种情况:
1)一般情况:临时性对象的被摧毁,应该是对完整表达式(full-expression)求值过程中的最后一个步骤。该完整表达式造成临时对象的产生。
例:
#include<iostream>
using namespace std;
class A
{
public:
A(int i): m_i(i)
{
cout << "A(): "<< m_i << endl;
}
~A()
{
cout << "~A(): "<< m_i << endl;
}
A operator+(const A& rhs)
{
cout << "Aoperator+(const A& rhs)" << endl;
return A(m_i + rhs.m_i);
}
int m_i;
};
int main()
{
A a1(1), a2(2);
a1 + a2;
cout <<"------------------------------------" << endl; //运行到这里,a1 + a2产生的临时变量已经被释放
return 0;
}
运行结果:
A(): 1
A(): 2
A operator+(const A& rhs)
A(): 3
~A(): 3
------------------------------------
~A(): 2
~A(): 1
两个例外:
2)凡含有表达式执行结果的临时性对象,应该存留到object的初始化操作完成为止。
例:
#include<iostream>
using namespace std;
class A
{
public:
A(int i = 0): m_i(i)
{
cout << "A(): "<< m_i << endl;
}
~A()
{
cout << "~A(): "<< m_i << endl;
}
A operator+(const A& rhs)
{
cout << "Aoperator+(const A& rhs)" << endl;
return A(m_i + rhs.m_i);
}
A& operator=(const A& rhs)
{
cout << "A&operator=(const A& rhs)" << endl;
m_i += rhs.m_i;
return *this;
}
int m_i;
};
int main()
{
A a1(1), a2(2);
A a3;
a3 = a1 + a2; //a1 + a2产生的临时变量在a3的赋值操作完成后,才释放
return 0;
}
运行结果:
A(): 1
A(): 2
A(): 0
A operator+(const A& rhs)
A(): 3
A& operator=(const A& rhs)
~A(): 3
~A(): 3
~A(): 2
~A(): 1
3)如果一个临时性对象被绑定于一个reference,对象将残留,直到被初始化之reference的生命结束,或直到临时对象的生命范畴(scope)结束——视哪一种情况先到达而定。
例:
#include<iostream>
using namespace std;
class A
{
friend ostream& operator<<(ostream& os, const A&);
public:
A()
{
}
A(const A&)
{
cout << "A(constA&)" << endl;
}
~A()
{
cout << "~A()"<< endl;
}
};
ostream& operator<<(ostream&os, const A&)
{
os << "ostream& operator<<(ostream&os, const A&)" << endl;
return os;
}
const A&f(const A& a)
{
return a;
}
int main(intargc, char* argv[])
{
{
const A& a = A();
cout << "-------------------"<< endl;
}//直到被初始化之reference的生命结束
cout << f(A()) << endl; //直到临时对象的生命范畴(scope)结束:
//临时对象的const引用在f的参数上(而不是返回值)。
//这个引用在f()返回的时候就结束了,但是临时对象未必销毁。
cout << "-------------------" << endl;
return 0;
}
运行结果:
-------------------
~A()
ostream& operator<<(ostream& os, const A&)
~A()
-------------------
参考:
《深度探索C++对象模型》6.3节 P270-P275
《C++标准(2003)》12.2节
自己测试及结果
头文件a.h
// Classautomatically generated by Dev-C++ New Class wizard
#ifndef A_H
#define A_H
#include<iostream>
/*
* No description
*/
class A
{
public:
// class constructor
A(inti=0);
// class destructor
~A();
friendA operator+(const A &lhs,const A &rhs);
friendstd::ostream& operator<<(std::ostream& os, const A&);
A&operator=(const A &);
intGet(){return m_i;}
private:
int m_i;
};
#endif // A_H
源文件a.cpp
#include"a.h" // class's header file
// class constructor
A::A(int i=0):m_i(i)
{
std::cout<<"对象地址:"<<this<<" constructor:A()"<<m_i<<std::endl;
}
A::~A()
{
std::cout<<"对象地址:"<<this<<" deconstructor:~A()"<<m_i<<std::endl;
}
A operator+(const A &lhs,const A&rhs)
{
std::cout<<"operator+"<<std::endl;
return A(lhs.m_i+rhs.m_i);
}
A& A::operator=(const A &org)
{
std::cout<<"operator="<<std::endl;
m_i=org.m_i;
return *this;
}
std::ostream& operator<<(std::ostream&os, const A&)
{
os << "ostream& operator<<(ostream& os, constA&)" <<std::endl;
return os;
}
主要的源文件main.cpp
#include<cstdlib>
#include<iostream>
#include"a.h"
using namespace std;
const A& f(const A& a)
{
cout<<"f(const A& a)"<<endl;
return a;
}
void test1()
{
cout<<"\n---------test1----------"<<endl;
Alhs(1),rhs(2);
lhs+rhs;
cout << "***************" << endl;
}
void test2()
{
cout<<"\n---------test2----------"<<endl;
Aa1(1),a2(2),a3;
a3 = a1 + a2; //a1 + a2产生的临时变量在a3的赋值操作完成后,才释放
cout << "***************" << endl;
}
void test5()
{
cout<<"\n---------test5----------"<<endl;
cout<<"一个变量可以给多个引用赋初值,但是一个引用只能对应一个对象"<<endl;
int i=0;
int &a=i;
a=10;
cout<<i<<endl;
int &b=i;
b=11;
cout<<i<<endl;
}
void test3()
{
cout<<"\n---------test3----------"<<endl;
const A& a = A();
cout << "***************" << endl;
}
void test4()
{
cout<<"\n---------test4----------"<<endl;
cout << f(A()) ; //直到临时对象的生命范畴(scope)结束:
cout<<"+++++"<<endl; //临时对象的const引用在f的参数上(而不是返回值)。
//这个引用在f()返回的时候就结束了,但是临时对象未必销毁。
cout << "***************" << endl;
}
int main(int argc, char *argv[])
{
test1();
cout<<"---------end test1----------\n"<<endl;
test2();
cout<<"---------end test2----------\n"<<endl;
test3();
cout<<"---------end test3----------\n"<<endl;
test4();
cout<<"---------end test4----------\n"<<endl;
test5();
cout<<"---------end test5----------\n"<<endl;
system("PAUSE");
return EXIT_SUCCESS;
}
结果与分析
第一个测试块:
void test1()
{
cout<<"\n---------test1----------"<<endl;
Alhs(1),rhs(2);
lhs+rhs;
cout << "***************" << endl;
}
很明显的在执行完lhs+rhs后临时对象析构。加法操作符重载函数
A operator+(const A &lhs,const A&rhs)
{
std::cout<<"operator+"<<std::endl;
return A(lhs.m_i+rhs.m_i);
}
产生临时对象A(lhs.m_i+rhs.m_i)。在这个函数执行完后这个临时变量析构。
第二个测试块
void test2()
{
cout<<"\n---------test2----------"<<endl;
Aa1(1),a2(2),a3;
a3 = a1 + a2; //a1 + a2产生的临时变量在a3的赋值操作完成后,才释放
cout << "***************" << endl;
}
这里调用了俩个操作符的重载加法操作符和赋值操作符。首先是以a1和a2为参数调用+操作符。
A operator+(const A &lhs,const A&rhs)
{
std::cout<<"operator+"<<std::endl;
return A(lhs.m_i+rhs.m_i);
}
产生一个临时对象A(lhs.m_i+rhs.m_i),到这里没有结束,要继续调用赋值操作符=。这个临时对象其实是作为赋值操作的参数(const A &org= A(lhs.m_i+rhs.m_i))
有一个引用&org绑定到了这个临时对象。而org引用是在赋值操作符调用结束后生命结束。所以知道赋值操作符调用结束后,临时对象才销毁。【个人认为—如果有一个引用绑定到一个临时对象,或者是有多个引用绑定到这个临时对象,那么只有到所有这些引用的生命结束,临时对象才会销毁。这是完全合理的,试想如果一个引用绑定到了一个临时对象,引用存在的时候这个对象必然是存在的。想想引用是什么,他只是变量的一个别名。要有别名的话,这个对象肯定要存在才可以】
A& A::operator=(const A &org)
{
std::cout<<"operator="<<std::endl;
m_i=org.m_i;
return *this;
}
第三个测试块
void test3()
{
cout<<"\n---------test3----------"<<endl;
const A& a = A();
cout << "***************" << endl;
}
引用a结束生命的时候临时对象销毁。
第四个测试块
void test4()
{
cout<<"\n---------test4----------"<<endl;
cout << f(A()) ; //直到临时对象的生命范畴(scope)结束:
cout<<"+++++"<<endl; //临时对象的const引用在f的参数上(而不是返回值)。
//这个引用在f()返回的时候就结束了,但是临时对象未必销毁。
cout << "***************" << endl;
}
这个测试块比较复杂,但是也是比较能说明问题
里面调用了俩个函数
const A& f(const A& a)
{
cout<<"f(const A& a)"<<endl;
return a;
}
其中这个f函数比较有意思,值得分析临时对象和引用的关系。
在执行这个f(A())表达式的时候,A()产生了一个临时对象,以这个临时对象为参数调用函数f,这里其实是个临时对象起了个别名,再调用传参的时候const A& a= A()。按道理应该a这个引用生命结束的时候(即f函数调用结束的时候),临时对象就得销毁了。但是并不是这样,这主要是因为函数f它又返回了一个临时对象的引用,相当于这个临时对象的一个引用生命结束了,但是它另外一个引用的生命还没有结束。那么临时对象的是还没有完,因为还有引用绑定它。它不能销毁。
std::ostream& operator<<(std::ostream&os, const A&)
{
os << "ostream& operator<<(ostream& os, constA&)" <<std::endl;
return os;
}
继续把这个引用传给输出操作符<<。这个时候看到了希望,因为临时对象的另外一个引用在这个函数调用完成的时候生命结束了,临时对象总算可以安息了,这时候析构。
第五个测试块
这个比较简单。不解释