对象优化学习笔记
对象使用过程中调用了哪些方法?
构造函数、析构函数、拷贝构造函数、赋值运算符重载函数。
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a = 5, int b = 5) : ma(a), mb(b)
{
cout << "Test(a, b)" << endl;
cout << a << " " << b << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
Test(const Test &src) : ma(src.ma), mb(src.mb)
{
cout << "Test(const Test& src)" << endl;
}
void operator=(const Test &src) //operator一定要拼写正确
{
ma = src.ma;
mb = src.mb;
cout << "operater= (const Test& src)" << endl;
}
private:
int ma;
int mb;
};
Test t1(10, 10);
int main()
{
Test t2(20, 20);
Test t3 = t2;
Test t4_ = Test(35, 35);
static Test t4 = Test(30, 30);
t2 = Test(40, 40);
t2 = (Test)(50, 50);
t2 = 60;
Test *p1 = new Test(70, 70);
Test *p2 = new Test[2];
Test *p3 = &Test(80, 80);
const Test &p4 = Test(90, 90);
cout << "-------------------" << endl;
delete p1;
delete[] p2;
return 0;
}
Test t5(100, 100);
/* 打印输出
Test(a, b)
10 10 //Test t1(10, 10);
Test(a, b)
100 100 //Test t5(100, 100);
Test(a, b)
20 20 //Test t2(20, 20);
Test(const Test& src) //Test t3 = t2; 定义阶段,不会调用赋值运算符重载,而是调用拷贝构造
Test(a, b)
35 35 //Test t4_ = Test(35, 35); 编译器优化,不会生成临时对象再赋值,而是直接构造
Test(a, b)
30 30 //static Test t4 = Test(30, 30); 同上
Test(a, b)
40 40
operater= (const Test& src)
~Test() //t2 = Test(40, 40); 先构造临时对象,然后调用赋值运算符重载进行赋值,赋值完成后,临时对象析构
Test(a, b)
50 5
operater= (const Test& src)
~Test() //t2 = (Test)(50, 50); 过程同上
Test(a, b)
60 5
operater= (const Test& src)
~Test() //t2 = 60;
Test(a, b)
70 70 //Test *p1 = new Test(70, 70); 堆上分配内存,并构造对象,此时不会析构
Test(a, b)
5 5
Test(a, b)
5 5 //Test *p2 = new Test[2]; 动态分配数组,采用默认构造函数构造了两个对象
Test(a, b)
80 80
~Test() //Test *p3 = &Test(80, 80); 指针指向临时对象的地址。先构造临时对象,语句完成后析构,指针变成野指针
Test(a, b)
90 90 //const Test &p4 = Test(90, 90); 常引用,构造临时对象,语句完成后不析构 (c++11后只允许常引用引用临时对象)
-------------------
~Test() //析构p1指向的对象
~Test()
~Test() //析构p2动态数组上的对象
~Test() //析构p4引用的对象
~Test() //析构t4_
~Test() //析构t3
~Test() //析构t2
~Test() //析构t4,t4是静态局部变量,和全局变量t1,t5存储在数据段上,最后才析构,析构顺序与构造顺序相反
~Test() //析构t5
~Test() //析构t1
*/
C++效率本身不低,关键在于开发者:减少对象使用过程中调用的方法(对象优化)。
函数调用过程中对象调用的方法太多
实例:
#include <iostream>
using namespace std;
class Test
{
public:
Test(int data = 10) : ma(data)
{
cout << "Test(int)" << endl;
}
~Test()
{
cout << "~Test() " << endl;
}
Test(const Test &src) : ma(src.ma)
{
cout << "Test(const Test&)" << endl;
}
void operator=(const Test &src)
{
ma = src.ma;
cout << "operator=(const Test&)" << endl;
}
int getData() const
{
return ma;
}
private:
int ma;
};
Test getObject(Test t)
{
int val = t.getData();
Test tmp(val); // 2. 调用构造函数,构造局部对象tmp
return tmp; // 3. 返回tmp:/*要把tmp对象拷贝main函数栈帧上的一个临时对象(此处步骤被编译器优化掉了)*/ 析构形参t
}
int main()
{
Test t1; //调用带默认参数的构造函数
Test t2; //调用带默认参数的构造函数
t2 = getObject(t1); /*
1. 函数传参,调用拷贝构造函数把对象拷贝给形参
4. 赋值运算符将main函数栈帧的临时对象赋值给t2, 然后析构临时对象
*/
return 0;
/*
析构t2
析构t1
*/
}
/*
Test(int)
Test(int)
Test(const Test&)
Test(int)
operator=(const Test&)
~Test() //析构tmp
~Test() //析构形参
~Test() //析构t2
~Test() //析构t1
*/
关闭编译器优化的输出结果:
-fno-elide-constructors # g++添加该参数,关闭编译器优化
Test(int)
Test(int)
Test(const Test&)
Test(int)
Test(const Test&) //main函数栈临时对象拷贝
~Test() //tmp析构
operator=(const Test&) //临时对象赋值给t2
~Test() //析构临时对象
~Test() //析构形参t(有的编译器,在main栈临时对象拷贝完成,tmp析构后,就析构了形参)
~Test()
~Test()
三条对象优化规则
-
函数参数传递过程中,对象优先按引用传递,不要按值传递(减少形参的拷贝构造和析构)
Test getObject(Test& t) { int val = t.getData(); Test tmp(val); return tmp; }
-
函数返回对象时,尽量返回临时对象,而不是先定义对象再返回。(临时对象被优化,直接再main栈上构造临时对象)
Test getObject(Test& t) { int val = t.getData(); // Test tmp(val); // return tmp; return Test(val); }
-
接受函数返回的对象时,直接初始化的时候接收,而不是先定义一个对象再接收。(main函数栈上的临时对象也被优化)
Test t1; // Test t2; // t2 = getObject(t1); Test t2 = getObject(t1);
添加带右值引用的拷贝构造和赋值运算符重载函数
Test(Test &&src) : ma(src.ma)
{
cout << "Test(const Test&)" << endl;
}
void operator=(Test &&src)
{
ma = src.ma;
cout << "operator=(const Test&)" << endl;
}