您的位置:首页 > 编程语言 > C语言/C++

C++右值引用完美展示与原理介绍

2016-08-23 18:38 405 查看
直接上代码,以自定义类MyString来演示创建多个对象却不用开辟新内存,也不用拷贝内存:

下面的getString函数内部,创建了三个对象,但是它们的资源却在像接力棒一样的传给下一个。从而不用开辟新内存,也不用拷贝内容。

最后一个对象用于真正的打印工作。

原理:

T&& std::move(const T& t) 

std::move用于返回对象的右值引用
而MyString的构造函数接受一个右值引用对象
MyString的构造函数在得到右值引用对象后交换资源,从而实现了偷梁换柱。避免了内存的重新开辟、拷贝、释放的过程。

总结:

从本例代码来看,右值引用相当于在参数传递的方式上增加了一种传参的形式。

原有的传参形式:

传地址:T*  C语言用法
传引用:T&  常用于修改对象
传应用:const T&  常用于只读对象
传值: T  常用于小型对象非频繁传值
传右值引用: T&& 常用于临时对象的资源交换,复杂对象避免拷贝

//// move example
#include <utility>      // std::move
#include <iostream>     // std::cout
#include <vector>       // std::vector
#include <string>       // std::string
using namespace std;

class MyString
{
friend ostream& operator<<(ostream& os, const MyString& str)
{
return	os<<str.m_pData;
}
public:
MyString(void)
:m_pData(nullptr),m_length(0),m_id(++s_i)
{
cout<<"MyString("<<m_id<<")"<<endl;
}
~MyString()
{
cout<<"~MyString("<<m_id<<")"<<endl;
Clear();
}
MyString(const char* _pData, int _length)
:m_pData(nullptr),m_length(0),m_id(++s_i)
{
cout<<"MyString(const char*,int,"<<m_id<<")"<<endl;
Copy(_pData, _length);
}
MyString(const MyString& _strFrom)
:m_pData(nullptr),m_length(0),m_id(++s_i)
{
cout<<"MyString("<<m_id<<", const MyString& "<<_strFrom.m_id<<" )"<<endl;
if (_strFrom.m_pData == m_pData)
{
//do nothing
}
else
{
Copy(_strFrom.m_pData, _strFrom.m_length);
}
}
//使用右值引用来创建对象时,使用资源交换来避免内存拷贝和重新创建
MyString(MyString&& _strFrom)
:m_pData(nullptr),m_length(0),m_id(++s_i)
{
cout<<"MyString("<<m_id<<", MyString&& "<<_strFrom.m_id<<" )"<<endl;
if (_strFrom.m_pData == m_pData)
{
//do nothing
}
else
{
swap(m_pData,_strFrom.m_pData);
swap(m_length,_strFrom.m_length);
}
}

protected:
void Clear(void)
{
if (nullptr != m_pData)
{
delete[] m_pData;
m_pData = nullptr;
m_length = 0;
}
}
void Copy(const char* _pData, int _length)
{
Clear();
m_pData = new char[_length];
for (size_t i = 0; i< _length; ++i)
{
m_pData[i] = _pData[i];
}

m_length = _length;
}
private:
char* m_pData;
int m_length;

int m_id;
static int s_i;
};

int MyString::s_i = 0;

MyString getMyString(void)
{
//下面的代码创建了三个MyString对象,只发生了1次开辟内存,0次内存拷贝
MyString s("12345",6);//id == 1
MyString s1(move(s));//id == 2
return move(s1);//id == 3 这个被函数返回
//~MyString(2)
//~MyString(1)
}

int main () {

cout<<getMyString()<<endl;//打印的是函数返回的id == 3的那个对象

return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: