右值引用优化性能,避免深拷贝

浅拷贝与浅赋值

      对于含有堆内存的类类型,我们需要提供深拷贝的拷贝构造函数,如果使用默认构造函数,默认重载赋值运算符函数(简称赋值函数),会导致堆内存的重复删除。

class Mystring
{
	char* str;
public:
	Mystring(const char* p = nullptr)
	{
		if (p != nullptr)
		{
			int n = strlen(p + 1);
			str = new char[n];
			strcpy_s(str, n, p);
		}
		else
		{
			str = new char[1];
			*str = '\0';
		}
		cout << "Create Mystring:" << this << endl;
	}
	Mystring(const Mystring& st)
	{
		str = st.str;
		cout << "Copy Create Mystring: " << this << endl;
	}
	Mystring& operator =(const Mystring& st)
	{
		if (this != &st)
		{
			str = st.str;
		}
		cout << this << "Mystring &operator=:" << &st << endl;
		return *this;
	}
	~Mystring()
	{
		delete[]str;
		str = nullptr;
		cout << "Destroy Mystring" << endl;
	}
};
int main()
{
	Mystring s1("yhping");
	Mystring s2(s1);
}

 若使用旧对象去构造新对象,调用拷贝构造函数,若调用的是浅拷贝,则两个对象指向同一块内存空间,若析构会导致堆内存的重复删除,就会出现非法访问。

深拷贝与深赋值

class Mystring
{
	char* str;
public:
	Mystring(const char* p = nullptr)
	{
		if (p != nullptr)
		{
			int n = strlen(p)+1;
			str = new char[n];
			strcpy_s(str, n, p);
		}
		else
		{
			str = new char[1];
			*str = '\0';
		}
		cout << "Create Mystring:" << this << endl;
	}
	Mystring(const Mystring& st)
	{
		int n = strlen(st.str) + 1;
		str = new char[n];
		strcpy_s(str, n, st.str);
		cout << "Create Copy Mystring:" << this << endl;
	}
	Mystring& operator=(const Mystring& st)
	{
		if (this != &st)
		{
			delete[]str;
			int n = strlen(st.str)+1;
			str = new char[n];
			strcpy_s(str, n, st.str);
		}
		cout << this << "Mystring &operator=:" << &st << endl;
		return *this;
	}
	~Mystring()
	{
		delete[]str;
		str = nullptr;
		cout << "Destroy Mystring" << endl;
	}
	void Printstring()const
	{
		cout << str << endl;
	}
};
Mystring Getstring()
{
	Mystring str("yhphello");
	return str;
}
int main()
{
	Mystring s1("yhping");
	s1.Printstring();
	s1 = Getstring();
	s1.Printstring();
}

 上面函数的Getstring函数将返回局部对象str,通过str拷贝一个临时对象作为返回值来用。此时的临时对象就是将亡值对象,str对象在拷贝完成之后就销毁啦,将亡值对象给是

赋值完后也销毁了,如果对象占用很大的堆内存,那么这个拷贝构造的代价会很大。带来了额外的性能损耗。有没有方法避免临时对象的拷贝构造。当然有办法。

移动构造和移动赋值

移动语义是通过右值引用来匹配(将亡值)临时值

class Mystring
{
	char* str;
public:
	Mystring(const char* p = nullptr)
	{
		if (p != nullptr)
		{
			int n = strlen(p)+1;
			str = new char[n];
			strcpy_s(str, n, p);
		}
		else
		{
			str = new char[1];
			*str = '\0';
		}
		cout << "Create Mystring:" << this << endl;
	}
	Mystring(const Mystring& st)
	{
		int n = strlen(st.str) + 1;
		str = new char[n];
		strcpy_s(str, n, st.str);
		cout << "Create Copy Mystring:" << this << endl;
	}
	Mystring& operator=(const Mystring& st)
	{
		if (this != &st)
		{
			delete[]str;
			int n = strlen(st.str)+1;
			str = new char[n];
			strcpy_s(str, n, st.str);
		}
		cout << this << "Mystring &operator=:" << &st << endl;
		return *this;
	}
	Mystring(Mystring&& st)
	{
		str = st.str;
		st.str = nullptr;
		cout << "Move Copy Create Mystring " << this << endl;
	}
	Mystring& operator=(Mystring&& st)
	{
		if (this == &st)
		{
			return *this;
		}
		if (this->str == st.str)
		{
			st.str == nullptr;
			return *this;
		}
		delete []str;
		str = st.str;
		st.str = nullptr;
		cout << "Move Mystring&operator=" << this << endl;
	}
	~Mystring()
	{
		delete[]str;
		str = nullptr;
		cout << "Destroy Mystring" << endl;
	}
	void Printstring()const
	{
		cout << str << endl;
	}
};
Mystring Getstring()
{
	Mystring str("yhphello");
	return str;
}
int main()
{
	Mystring s1("yhping");
	s1.Printstring();
	s1 = Getstring();
	s1.Printstring();
}

 上面的代码中加入了移动构造(Move Construct)和移动赋值,从移动构造和移动赋值函数的实现中可以看到,它的参数是一个右值引用类型的参数Mystring&&。这里的Mystring&&用来根据参数是左值还是右值来建立分支,如果是临时值(将亡值),则会选择移动构造函数,移动构造函数只是将tmp对象资源做了浅拷贝,不需要对其深拷贝,从而避免了额外的拷贝,提高性能。这就是移动语义。右值引用的一个重要目的是支持移动语义。

移动语义的特点:

1.移动语义可以将系统资源(堆或者系统对象等)通过浅拷贝的方式从一个对象转移到另一个对象,这样就能减少对堆区动态内存分配、数据拷贝、以及对堆区动态内存的释放,可以大幅提高C++程序的性能。

2/消除了对临时对象和自身资源(创建和销毁)的维护而造成的性能浪费。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秉麟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值