右值引用之移动语义

本文翻译自关于右值引用解释的经典文章,如果英文还可以的话,直接去看英文原文。thbecker.net/articles/rvalue_references/section_01.html

右值引用是c++中的一个特性,并且已经入驻c++11标准,可能大家一开始接触的时候感觉有点难以理解,但是他的确是很好用的一个玩意儿。

右值引用解决了两个问题:

1.move语义 2.完美转发。

我们接下来先简单介绍一下move语义,但是介绍move语义之前,我们需要先介绍左值和右值的含义。

在C语言中,我们给出左值的定义为:左值是一个表达式e,那么他既可以出现在赋值操作符的左边,也可以出现在右边。右值是:只允许出现在赋值操作符右边的表达式。

int a = 42;

int b = 43;



// a b 都是左值

a = b; // ok

b = a; // ok

a = a * b; // ok



// a * b 是右值

int c = a * b; // ok, 右值出现在=右边

a * b = 42; // error, 右值不允许出现在=左边

 那么在c++中,左右值的定义也差不多,但是有一点点变化。在c++中,左值是:你可以对它取地址(&)操作的表达式,右值是非左值的表达式。

 // 左值:

  //

  int i = 42;

  i = 43; // ok, i 是左值

  int* p = &i; // ok, i 是左值

  int& foo();

  foo() = 42; // ok, foo() 是左值

  int* p1 = &foo(); // ok, foo() 是左值



  // 右值:

  //

  int foobar();

  int j = 0;

  j = foobar(); // ok, foobar() 是右值

  int* p2 = &foobar(); // error, 不能取右值表达式的地址

  j = 42; // ok, 42 是右值

 

假设我们有一个类X,他有一个成员函数为一个指针,可能指向某些资源之类的。那么相应的构造、析构、拷贝等操作都是需要一些特殊的处理工作。

比如我们常见的std::vector,那么X的拷贝操作就类似下面这样:

X& X::operator=(X const & rhs) { // [...] // 先收回资源m_pResource // 对rhs的m_pResource指向的资源做拷贝操作 // 然后令m_pResource指向新的内存位置. // [...] }

或者你可能会遇到下面这种代码:

X foo();

X x;

x = foo();

那么第三句,也就是最后一句要执行三个操作:

1.释放原来x的资源。

2.克隆foo返回值中的资源给x的资源。

3.销毁释放返回值中的资源。

很显然,这是很低效的做法,更聪明的做法是swap操作,交换x和返回值x`的资源,然后原x的资源会被自动释放。

换句话说我们想做的就是:

...
swap(m_pResource,rhs.m_pResource);
...

这个就叫做move语义,在c++11中,通过重载可实现这个特性:

X& X::operator=(<???> rhs) { // [...] // swap(m_pResource,rhs.m_pResource); // [...] }

 那么这个???是个什么类型呢?当然首先它应该是一种引用类型,减少不必要的值拷贝,然后我们还想它和传统的引用类型分开,因为我们希望当右操作数为右值的时候,调用???这个重载,而当右操作数为左值的时候,调用原始的引用赋值构造,那么好吧,那我们就把???叫做“右值引用”好了。

你可能感兴趣的:(移动)