C++移动语义

左值右值

左右值的概念
简单来讲,左值(lvalue: located value)就是可以拿到地址的值。右值就是不能拿到地址的值。
比如
int a = 10; a是左值,10是右值。
int a = func(); a是左值,func()是右值。
右值引用符号: &&

int&& ra = 10;	//ra是右值引用,但其本身是一个左值(因为可以拿到它的地址),10是右值

程序判断左右值:
判断类型是否是左右值:
c++自带的判断函数:

std::is_lvalue_reference<type>	//左值引用
std::is_rvalue_reference<type>	//右值引用

例子:

{
    
    
        cout << "is lvalue: " << endl;
        cout << "int:" << is_lvalue_reference<int>::value << ", ";
        cout << "int&:" << is_lvalue_reference<int&>::value <<", ";
        cout << "int&&:" << is_lvalue_reference<int&&>::value << ", ";
        cout << "int*:" << is_lvalue_reference<int*>::value << ". ";
        cout << "\n";

        cout << "is rvalue: " << endl;
        cout << "int:" << is_rvalue_reference<int>::value << ", ";
        cout << "int&:" << is_rvalue_reference<int&>::value <<", ";
        cout << "int&&:" << is_rvalue_reference<int&&>::value << ", ";
        cout << "int*:" << is_rvalue_reference<int*>::value << ". ";
        cout << "\n";
        int&& ra = 10;
        cout << "decltype(ra):" << is_rvalue_reference<decltype(ra)>::value << endl;
    }

运行结果:
在这里插入图片描述

移动语义

C++std::move 函数。
定义:

template <class T>
typename remove_reference<T>::type&& move (T&& arg) noexcept;

作用:
返回一个arg的右值引用。
官方例子:

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

int main () {
    
    
  std::string foo = "foo-string";
  std::string bar = "bar-string";
  std::vector<std::string> myvector;

  myvector.push_back (foo);                    // copies
  myvector.push_back (std::move(bar));         // moves

  std::cout << "myvector contains:";
  for (std::string& x:myvector) std::cout << ' ' << x;
  std::cout << '\n';
  cout << "foo: " << foo << endl;
  cout << "bar: "<<bar << endl;
  return 0;
}

第一次调用myvector.push_back复制了foo的值到vector(foo保持原来的值。第二次调用使用了move函数把bar的值移动到vector里面(bar失去了他的值)。
输出:

myvector contains: foo-string bar-string
foo: foo-string
bar: 

移动构造函数

移动构造函数的输入是右值,编译器会自动调用移动构造函数来减少不必要的深度拷贝,比如下面的例子,因为CatBorn函数里的cat即将析构,是一个右值,所以编译器调用移动构造函数,把cat的pweight资源拿过来用。

class Cat
{
    
    
public:
    Cat(int w = 1): pweight(new int(w)){
    
    
        cout << "cat normal constructor." <<endl;
    }
    Cat(const Cat& cat) : pweight(new int(*(cat.pweight))){
    
    	//拷贝构造函数
        cout << "cat copy constructor." << endl;
    }
    Cat(Cat&& cat): pweight(cat.pweight){
    
    	//移动构造函数
        cat.pweight = nullptr;
        cout << "cat move constructor" << endl; 
    }
    void Cry(){
    
    
        cout << "cat cry: " << *pweight;
    }
private:
    int* pweight;
};

Cat CatBorn()
{
    
    
    Cat cat;
    return cat;
}

int main()
{
    
    
	CatBorn().Cry();
}

运行输出:
cat normal constructor.
cat move constructor
cat cry: 1

猜你喜欢

转载自blog.csdn.net/qq_40541268/article/details/126252106