一.先让我们来从代码中看下对象的生存周期:【代码说明】
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时释放。生存期由用户指定,灵活。但有内存泄露等问题!!