一.先让我们来从代码中看下对象的生存周期:【代码说明】
class Test{ public: Test(int a=10, int b=10) { ma = a; mb = b; cout<<"ma:"<<ma<<" mb:"<<mb<<endl; cout<<"Test(int) "<<this<<endl; } Test(const Test &src) { ma = src.ma; mb = src.mb; cout<<"ma:"<<ma<<" mb:"<<mb<<endl; cout<<"Test(const Test&) "<<&src<<"->"<<this<<endl; } void operator=(const Test &src) { ma = src.ma; mb = src.mb; cout<<"ma:"<<ma<<" mb:"<<mb<<endl; cout<<"operator=(const Test&) "<<&src<<"->"<<this<<endl; } ~Test() { cout<<"ma:"<<ma<<" mb:"<<mb<<endl; cout<<"~Test() "<<this<<endl; } void Show(){cout<<"ma:"<<ma<<" mb:"<<mb<<endl;} int GetValue1(){return ma;} int GetValue2(){return mb;} private: int ma; int mb;};Test GetObject(Test t){ int a = t.GetValue1(); int b = t.GetValue2(); Test tmp(a,b); return tmp;}int main(){ Test t1(10, 10); Test t2; t2=GetObject(t1); cout<<"-----------------"<<endl; t2.Show(); return 0;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
main()函数中类对象的生存周期:先构造t1,再构造t2, t1拷贝构造给t ,构造tmp,tmp拷贝构造临时变量,析构tmp,析构t,临时变量赋值给t2,析构临时变量,
析构t2 ,t1,完。
但上述代码仍需继续优化,将其GetObject()函数稍作改变:
Test GetObject(Test &t){ int a = t.GetValue1(); int b = t.GetValue2(); return Test(a, b);}int main(){ Test t1(10, 10); Test t2; t2=GetObject(t1); t2.Show(); return 0;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
//这里的main()函数先构造t1 t2,子函数产生返回临时变量,临时变量赋值给t2,析构临时变量,析构t2 析构t1,是不是和上一步相比少了些许构造和析构呢?答案是肯定的。
二.我们还可以进一步优化:
Test GetObject(Test &t){ int a = t.GetValue1(); int b = t.GetValue2(); return Test(a, b);int main(){ Test t1(10, 10); Test t2=GetObject(t1); t2.Show(); return 0;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
//当我们在主函数中直接定义并初始化的时候,与上一步相比,少了一次构造和赋值,也少了一次析构。因为这里是临时对象构造一个新的对象,临时对象被优化。相当于在返回的时候直接就构造了t2。
三.接下来看另外的一个例子,进一步总结说明:
class Cgoods{ public: Cgoods(char *n,int m,float p); Cgoods(const Cgoods &src); void operator=(const Cgoods &src); ~Cgoods(); private: char* mName; int mAmount; float price;};Cgoods ::Cgoods(char *n,int m,float p){ cout<< this<<endl; cout<< "Cgoods(char *n,int m,float p)"<<endl; mName=new [strlen(n)+1]; strcpy(mName,n); mAmount=m; price=p;}Cgoods ::Cgoods(const Cgoods &src){ cout<<&src<<"->"<< this<<endl; cout<<"Cgoods(const Cgoods &src)"<<endl; mName=new [strlen(src.mName)+1]; strcpy(mName,src.mName); mAmount=src.mAmount; price=src.price;}void Cgoods ::operator=(const Cgoods &src){ cout<<&src<<"->"<< this<<endl; cout<<"operator=(const Cgoods &src)"<<endl; if (&src==this) { return ; } delete []mName; mName=NULL; mName=new [strlen(src.mName)+1]; strcpy(mName,src.mName); mAmount=src.mAmount; price=src.price;}Cgoods::~Cgoods(){ delete []mName; mName=NULL;} void fun(Cgoods *pgood) { cout<<"call func"<<endl; }int main(){ func(Cgoods ("shangpin1",14,14.1)); Cgoods good1("shangpin1",14,14.1); Cgoods good2(good1); Cgoods("shangpin1",15,15.1) Cgoods good3=Cgoods("shangpin1",15,15.1); good3=Cgoods("shangpin1",16,16.1); good3=(Cgoods)("shangpin1",16,16.1); good3=40.1; Cgoods good4=60.8; Cgoods *good5=&Cgoods("shangpin1",17,17.1); Cgoods &good6=Cgoods("shangpin1",18,18.1); return 0;}
四.其他的几点总结:
1)创建与销毁(特别注意的):
- 创建顺序
外部静态对象or外部对象优先于main函数 - 销毁顺序
和创建顺序相反,注意静态对象会在main函数执行完才会销毁
2)内存的三种分配方式:
- 从静态存储区分配:
- 此时的内存在程序编译的时候已经分配好,并且在程序的整个运行期间都存在。全局变量,static变量等在此存储
- 在栈区分配:
- 相关代码执行时创建,执行结束时被自动释放。局部变量在此存储。栈内存分配运算内置于处理器的指令集中,效率高,但容量有限.
- 在堆区分配:
- 动态分配内存。用new/malloc时开辟,delete/free时释放。生存期由用户指定,灵活。但有内存泄露等问题!!