c++(6)----移动语义

为什么需要移动语义

一些场景

#include <iostream>
#include <cstring>

using namespace  std;

class A{
public:
   A():i(new int[20]){
      cout<<"class A construct!"<<endl;
   }
   A(const A &a):i(new int[20]){
      memcpy(a.i,i,20*sizeof(int));
      cout<<"class A copy!"<<endl;
   }
   ~A(){
      delete []i;
      cout<<"class A destruct!"<<endl;
   }

private:
   int *i;
};

A get_A_value(){
    return A();
}
void pass_A_by_value(A a){

}
int main(){
    A a = get_A_value();
    return 0;
}
View Code
g++ test01.cpp -o main -fno-elide-constructors -std=c++11

运行结果如下:
class A construct!
class A copy!
class A destruct!
class A copy!
class A destruct!
class A destruct!

 

左值:有标识符、可以取地址的表达式

   如:变量、函数或数据成员的名字

       返回左值引用的表达式,如 ++x、x = 1、cout  <<  ' '   ,字符串字面量如"hello world"

         左值可以绑定到左值引用的参数,如 T&。一个常量只能绑定到常左值引用,如 const T&。

纯右值 prvalue 是没有标识符、不可以取地址的表达式,一般也称之为“临时对象”。
左值可以绑定到左值引用的参数,如 T&。一个常量只能绑定到常左值引用,如 const T&。
返回左值引用的表达式,如 ++x、x = 1、cout << ' '

           

变量、函数或数据成员的名字

纯右值 : prvalue 是没有标识符、不可以取地址的表达式,一般为“临时对象”。

              返回非引用类型的表达式,如 x++、x + 1、make_shared<int>(42)

             除字符串字面量之外的字面量,如 42、true    

右值引用:

T&&

c++11 之前右值可以绑定到常左值引用(const T&)中,单不能绑定到非常左值引用(T &)中。

C++11引入右值引用 T&&,可以将右值绑定到又值引用类型中。

右值引用类型是左值,类型是右值引用的变量是一个左值!

#include <iostream>
#include <cstring>

using namespace  std;

class A{
public:
   A():i(new int[20]){
      cout<<"class A construct!"<<endl;
   }
   A(const A &a):i(new int[20]){
      memcpy(a.i,i,20*sizeof(int));
      cout<<"class A copy!"<<endl;
   }
  //  添加一个右值引用类型参数的构造函数
   A(A &&a) noexcept{
       i=a.i;
       if(i){
           a.i=nullptr;
       }
       cout<<"class A(A &&) copy!"<<endl;
   }
   ~A(){
      if(i) delete []i;
      cout<<"class A destruct!"<<endl;
   }

private:
   int *i;
};


A get_A_value(){
    return A();
}
void pass_A_by_value(A a){

}
g++ test01.cpp -o main -fno-elide-constructors -std=c++11
int main(){
    A a = get_A_value();
    return 0;
}

// 输出
class A construct!
class A(A &&) copy!
class A destruct!
class A(A &&) copy!
class A destruct!
class A destruct!

/**
A() 得到一个右值,匹配到右值类型的参数
**/
View Code
int main(){
    A a1;
    A a2 = a1;
    return 0;
}

// 输出
class A construct!
class A copy!
class A destruct!
class A destruct!

/**
a1 是一个左值
**/
View Code
int main(){
    A a1;
    A a2 = std::move(a1);
    return 0;
}

//输出
class A construct!
class A(A &&) copy!
class A destruct!
class A destruct!

/**
std::move(a1) ; 将一个左值引用强制转换乘一个右值引用
**/
View Code

移动语义的意义

使得在 C++ 里返回大对象(如容器)的函数和运算符成为现实,因而可以提高代码的简洁性和可读性

实现步骤:

1、分开拷贝构造 和 移动构造

2、右swap成员函数,支持和另外一个对象快速交换

3、在你的对象的名空间下,应当有一个全局的 swap 函数,调用成员函数 swap 来实现交换。支持这种用法会方便别人(包括你自己在将来)在其他对象里包含你的对象,并快速实现它们的 swap 函数。

4、实现通用的operator=

5、应当标为 noexcept。这对移动构造函数尤为重要

6、移动构造函数应当从另一个对象获取资源,清空其资源,并将其置为一个可析构的状态。

应当标为 noexcept。这对移动构造函数尤为重要
使得在 C++ 里返回大对象(如容器)的函数和运算符成为现实,因而可以提高代码的简洁性和可读性

posted on 2020-02-02 15:14  feihu_h  阅读(252)  评论(0)    收藏  举报

导航