首页 > 编程语言 > 详细

【C/C++】【类和对象】临时对象

时间:2020-07-21 11:57:15      阅读:63      评论:0      收藏:0      [点我收藏+]

临时对象

C++中真正的临时对象是不可见的,在源代码中不会出现,且不在堆上分配内存(在栈中),没有名字的对象;

//i++ ++i
//i++ 会产生一个临时对象,用来记录i的值;
int i = 1;
int &&r = i++; //i和r没关系 

产生临时对象的情况

临时对象可能发生于如下的三种情况,我们需要了解这些临时对象如何被产生和被销毁;以及如何避免产生临时对象,避免不必要的调用构造和析构;进一步提升程序的性能;

  1. 传值方式给函数传参
  2. 隐式类型转换
  3. 函数返回对象

传值方式给函数传参

  • 按照值传递的方式给函数传参,函数会产生一个实参的副本,在函数中所有的操作都是针对这个副本的,也正是因为这个原因,对副本的修改并不会影响实参的值;
  • 通过采用引用传值的方式,不用创建实参的副本,少调用一次拷贝构造和一次析构函数,同时可以通过形参来修改实参的值;
#include <iostream>
using namespace std;
class CTempValue
{
public:
	int m_val;
	int m_v;
public:
	CTempValue(int i = 0, int j = 0);
	CTempValue(const CTempValue& t) :m_val(t.m_val), m_v(t.m_v)
	{
		cout << "执行拷贝构造函数" << endl;
	}
	virtual ~CTempValue()
	{
		cout << "执行析构函数" << endl;
	}

	int add(CTempValue tmp); //普通函数
};
CTempValue::CTempValue(int i, int j):m_val(i), m_v(j)
{
	cout << "执行构造函数" << endl;
	cout << "m_val = " << m_val << endl;
	cout << "m_v = " << m_v << endl;
}

int CTempValue::add(CTempValue tmp)
{
	int tmp_val = tmp.m_val + tmp.m_v;
	tmp.m_val = 1000;
	return tmp_val;
}

int main()
{
	CTempValue tmp(10, 20); //构造函数执行
	int Sum = tmp.add(tmp); //拷贝构造函数和析构函数会执行
	//add的形式参数会拷贝实参 使用拷贝构造函数   
	//形参的释放 调用析构函数

	cout << "Sum = " << Sum << endl;
	cout << "tmp.m_val = " << tmp.m_val << endl;
}

通过引用传参解决


#include <iostream>
using namespace std;


class CTempValue
{
public:
	int m_val;
	int m_v;
public:
	CTempValue(int i = 0, int j = 0);
	CTempValue(const CTempValue& t) :m_val(t.m_val), m_v(t.m_v)
	{
		cout << "执行拷贝构造函数" << endl;
	}
	virtual ~CTempValue()
	{
		cout << "执行析构函数" << endl;
	}

	int add(CTempValue& tmp); //普通函数
};
CTempValue::CTempValue(int i, int j):m_val(i), m_v(j)
{
	cout << "执行构造函数" << endl;
	cout << "m_val = " << m_val << endl;
	cout << "m_v = " << m_v << endl;
}

int CTempValue::add(CTempValue& tmp)
{
	int tmp_val = tmp.m_val + tmp.m_v;
	tmp.m_val = 1000;
	return tmp_val;
}


int main()
{
	CTempValue tmp(10, 20); //构造函数执行
	int Sum = tmp.add(tmp); //拷贝构造函数和析构函数不会执行
	cout << "Sum = " << Sum << endl;
	cout << "tmp.m_val = " << tmp.m_val << endl;
}

类型转换

  • 将值赋给某个变量的时候(传递对象给一个参数),其类型和它即将绑定上去的参数类型不同会发生隐式类型转化;

示例1
将一个整型值赋值给一个CTempValue对象,会发生隐式类型转换;

  1. 会产生一个临时对象;
  2. 会调用拷贝赋值运算符把这个临时对象里面的各个成员赋值给sum对象
  3. 销毁这个临时创建的CTempValue对象
#include <iostream>
using namespace std;
class CTempValue
{
public:
	int m_val;
	int m_v;
public:
	CTempValue(int i = 0, int j = 0);
	CTempValue(const CTempValue& t) :m_val(t.m_val), m_v(t.m_v)
	{
		cout << "执行拷贝构造函数" << endl;
	}
	//拷贝赋值运算符
	CTempValue& operator=(const CTempValue& tmp)
	{
		m_val = tmp.m_val;
		m_v = tmp.m_v;
		cout << "执行拷贝赋值运算符" << endl;
		return *this;
	}
	virtual ~CTempValue()
	{
		cout << "执行析构函数" << endl;
	}

	int add(CTempValue& tmp); //普通函数
};
CTempValue::CTempValue(int i, int j):m_val(i), m_v(j)
{
	cout << "执行构造函数" << endl;
	cout << "m_val = " << m_val << endl;
	cout << "m_v = " << m_v << endl;
}

int CTempValue::add(CTempValue& tmp)
{
	int tmp_val = tmp.m_val + tmp.m_v;
	tmp.m_val = 1000;
	return tmp_val;
}
int main()
{
	CTempValue sum;
	sum = 1000; //会产生一个临时对象; 调用一次构造函数一次析构函数 
}

解决方法

  • 通过定义时初始化对象来达到不生成临时对象的目的;

  • =是定义时初始化;系统为对象预留空间 用1000构造对象,而且是直接构造在对象预留空间中;

    
    #include <iostream>
    using namespace std;
    class CTempValue
    {
    public:
    	int m_val;
    	int m_v;
    public:
    	CTempValue(int i = 0, int j = 0);
    	CTempValue(const CTempValue& t) :m_val(t.m_val), m_v(t.m_v)
    	{
    		cout << "执行拷贝构造函数" << endl;
    	}
    
    	//拷贝赋值运算符
    	CTempValue& operator=(const CTempValue& tmp)
    	{
    		m_val = tmp.m_val;
    		m_v = tmp.m_v;
    		cout << "执行拷贝赋值运算符" << endl;
    		return *this;
    	}
    	virtual ~CTempValue()
    	{
    		cout << "执行析构函数" << endl;
    	}
    
    	int add(CTempValue& tmp); //普通函数
    };
    CTempValue::CTempValue(int i, int j):m_val(i), m_v(j)
    {
    	cout << "执行构造函数" << endl;
    	cout << "m_val = " << m_val << endl;
    	cout << "m_v = " << m_v << endl;
    }
    int CTempValue::add(CTempValue& tmp)
    {
    	int tmp_val = tmp.m_val + tmp.m_v;
    	tmp.m_val = 1000;
    	return tmp_val;
    }
    int main()
    {
          /*	
          CTempValue sum;
    	sum = 1000;
          */ //会产生一个临时对象; 调用一次构造函数一次析构函数 一次拷贝赋值运算符
    	//1. 用1000创建CTempValue的临时对象
    	//2. 调用拷贝赋值运算符把这个临时对象里面的各个成员赋值给sum对象
    	//3. 销毁这个临时创建的CTempValue对象
    
    	CTempValue sum = 1000; //没有生成临时对象  =是定义时初始化;系统为sum预留空间  用1000构造sum对象,而且是直接构造在sum对象预留空间中;
    
    }
    

示例2

//统计字符ch在str中出现的次数
int total(const string &str, char ch) //将str绑定到string临时对象上  去掉const报错  系统不允许修改临时对象
{
	const char* p = str.c_str();
	int count = 0;
	return count;
}

int main()
{
	char mystr[100] = "hello world";
	int res = total(mystr, ‘o‘); //隐式类型转化 会产生临时对象string
	//c++只会为const引用产生临时对象,而不会为非const引用产生临时对象???
}

优化

函数返回对象

当函数需要返回一个对象,它会在栈中创建一个临时对象,存储函数的返回值。

范例1

#include <iostream>
using namespace std;
class CTempValue
{
public:
	int m_val;
	int m_v;
public:
	CTempValue(int i = 0, int j = 0);
	CTempValue(const CTempValue& t) :m_val(t.m_val), m_v(t.m_v)
	{
		cout << "执行拷贝构造函数" << endl;
	}
	//拷贝赋值运算符
	CTempValue& operator=(const CTempValue& tmp)
	{
		m_val = tmp.m_val;
		m_v = tmp.m_v;
		cout << "执行拷贝赋值运算符" << endl;
		return *this;
	}
	virtual ~CTempValue()
	{
		cout << "执行析构函数" << endl;
	}
	int add(CTempValue& tmp); //普通函数

};
CTempValue::CTempValue(int i, int j):m_val(i), m_v(j)
{
	cout << "执行构造函数" << endl;
	cout << "m_val = " << m_val << endl;
	cout << "m_v = " << m_v << endl;
}

int CTempValue::add(CTempValue& tmp)
{
	int tmp_val = tmp.m_val + tmp.m_v;
	tmp.m_val = 1000;
	return tmp_val;
}

CTempValue Double(CTempValue& tmp)
{
	CTempValue tmp_value; //构造 + 析构
	tmp_value.m_v = tmp.m_v * 2;
	tmp_value.m_val = tmp.m_val * 2;
	return tmp_value; //产生临时对象  调用拷贝构造函数和析构函数
}

int main()
{
	CTempValue x(10, 20); //构造 + 析构
	//Double(x);
	CTempValue&& y = Double(x); //临时对象是一种右值
	CTempValue z = Double(x);

}

优化


#include <iostream>
using namespace std;


class CTempValue
{
public:
	int m_val;
	int m_v;
public:
	CTempValue(int i = 0, int j = 0);
	CTempValue(const CTempValue& t) :m_val(t.m_val), m_v(t.m_v)
	{
		cout << "执行拷贝构造函数" << endl;
	}

	//拷贝赋值运算符
	CTempValue& operator=(const CTempValue& tmp)
	{
		m_val = tmp.m_val;
		m_v = tmp.m_v;
		cout << "执行拷贝赋值运算符" << endl;
		return *this;
	}

	virtual ~CTempValue()
	{
		cout << "执行析构函数" << endl;
	}

	int add(CTempValue& tmp); //普通函数

};
CTempValue::CTempValue(int i, int j):m_val(i), m_v(j)
{
	cout << "执行构造函数" << endl;
	cout << "m_val = " << m_val << endl;
	cout << "m_v = " << m_v << endl;
}

int CTempValue::add(CTempValue& tmp)
{
	int tmp_val = tmp.m_val + tmp.m_v;
	tmp.m_val = 1000;
	return tmp_val;
}

CTempValue Double(CTempValue& tmp)
{
	return CTempValue(tmp.m_val * 2, tmp.m_v * 2);
}
int main()
{
	CTempValue x(10, 20); //构造 + 析构
	//Double(x);

	CTempValue&& y = Double(x); //临时对象是一种右值
	//CTempValue z = Double(x);

}

范例2:类外运算符重载

class mynum
{
public:
	int x;
	int y;
};
mynum operator+(mynum& num1, mynum& num2)
{
	mynum res;
	res.x = num1.x + num2.x;
	res.y = num1.y + num2.y;
	return res;
}
int main()
{
	mynum num1;
	num1.x = 1;
	num1.y = 2;


	mynum num2;
	num2.x = 3;
	num2.y = 4;

	mynum num3 = num1 + num2;

}

优化


class mynum
{
public:
	int x;
	int y;
public:
	mynum(int x = 0, int y = 0) :x(x), y(y) {};
};
mynum operator+(mynum& num1, mynum& num2)
{
	return mynum(num1.x + num2.x, num1.y + num2.y);
}
int main()
{
	mynum num1;
	num1.x = 1;
	num1.y = 2;


	mynum num2;
	num2.x = 3;
	num2.y = 4;

	mynum num3 = num1 + num2;

}

参考:《More Effective C++》条款19(p98)

【C/C++】【类和对象】临时对象

原文:https://www.cnblogs.com/Trevo/p/13343866.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!