21天是肯定没法学会C++的。22天也不行。

C++11里引入了一个新的概念 :移动。 这个概念说简单其实很简单,因为它是介于拷贝和引用之间的一种概念。但还是有很多小伙伴表示不理解移动到底做了什么,如何理解移动

要想理解移动,先来介绍一个概念:左值与右值。

左值与右值

笼统来讲,左值就是能够对其取地址的值。反之就是右值(临时变量也是右值)。比如1, 2.0, true, nullptr这种纯值类型,就是妥妥的右值。再比如 int a = 100;a是左值,100是右值。在给a赋值的过程中,我们将右值拷贝到了左值。(其实并不是完全这样,编译器会做一定程度的优化,但为了方便理解,我们不考虑编译器的功劳)

两个栗子

在早期C++里,我们通常用指针或者引用来传递一个‌大变量,因为可以避免一次拷贝的开销。第一个栗子:如果我们有一个比较大的右值变量,我想将它传递给其他的函数,该如何避免/减少拷贝的开销呢?比较熟悉的朋友可能会说,我们可以传递 const & 来避免拷贝的开销。

没错,在C++11 之前,const & 可以对右值直接取引用。这样我们可以传递引用来避免拷贝的开销。那么下一个栗子就是,如果我们有一个比较大的右值变量,我想将它传递给其他的函数,‌又想要修改这个右值变量的值,该如何避免/减少拷贝的开销呢?

C++11 提出了一个概念:右值引用。语法是两个&。 它允许我们对右值进行直接引用。

移动

理解了右值之后,我们来思考一个问题。当我们进行赋值语句时,其实是构建了一个右值,然后复制给了左值。那么有没有花销更小的方法呢?答案就是移动

熟悉C++的都知道C++中有构造方法。构造方法又有拷贝构造赋值构造两种特殊的构造方法。C++11提出了新的构造类型:移动构造。也即方法接受的参数是一个右值,然后通过移动的方式,减少拷贝与销毁的开销,实现资源的转移。样式为: Type::Type(Type && rval)

另一个作用就是,std::move在移动的时候,可以 剥夺原变量的数据所有权。通常进行所有权转移时我们会显式调用std::move 方法。

vector来举例。

vector<int> a {1,2,3,4,5};
for (auto i : a){
    cout << i<< ", ";   // --> 1, 2, 3, 4, 5   
}
vector<int> b  = move(a);

for (auto i : a){
    cout << i<< endl;   // Nothing, moved to b
}
cout << "----" <<endl;
for (auto i :b){
    cout << i<< ", ";   // --> 1, 2, 3, 4, 5   
}

联通

C++ 11 中的移动语义使得我们在构造临时变量,减少构造与析构的消耗,并且可以显示表达所有权的转移。既增强了代码的运行效率,又增加了代码的可读性。

move不产生新变量,它只是c++的搬运工。

  1. 如果我们有一个比较大的右值变量,我想将它传递给其他的函数,‌又想要修改这个右值变量的值,该如何避免/减少拷贝的开销呢?

    引用啊

Leave a Reply