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

C++ 11中的move语义

2014-04-26 23:45 225 查看
http://www.cnblogs.com/tingshuo/archive/2013/01/21/2870035.html
http://www.cnblogs.com/tingshuo/archive/2013/01/22/2871328.html
一、深度拷贝与转移

string& operator=(string that)
    {
        std::swap(data, that.data);
        return *this;
    }
注意到我们是直接对参数that传值,所以that会像其他任何对象一样被初始化,那么确切的说,that是怎样被初始化的呢?对于C++ 98,答案是复制构造函数,但是对于C++ 11,编译器会依据参数是左值还是右值在复制构造函数和转移构造函数间进行选择。

1、如果是a=b,这样就会调用复制构造函数来初始化that(因为b是左值),赋值操作符会与新创建的对象交换数据,深度拷贝。这就是copy and swap 惯用法的定义:构造一个副本,与副本交换数据,并让副本在作用域内自动销毁。这里也一样。

2、如果是a = x + y,这样就会调用转移构造函数来初始化that(因为x+y是右值),所以这里没有深度拷贝,只有高效的数据转移。相对于参数,that依然是一个独立的对象,但是他的构造函数是无用的(trivial),因此堆中的数据没有必要复制,而仅仅是转移。没有必要复制他,因为x+y是右值,再次,从右值指向的对象中转移是没有问题的。

总结一下:复制构造函数执行的是深度拷贝,因为源对象本身必须不能被改变。而转移构造函数却可以复制指针,把源对象的指针置空,这种形式下,这是安全的,因为用户不可能再使用这个对象了。

二、右值引用

转移左值是十分危险的,但是转移右值却是很安全的。如果C++能从语言级别支持区分左值和右值参数,我就可以完全杜绝对左值转移,或者把转移左值在调用的时候暴露出来,以使我们不会不经意的转移左值。

C++ 11对这个问题的答案是右值引用。右值引用是针对右值的新的引用类型,语法是X&&。以前的老的引用类型X& 现在被称作左值引用(注意X&&不是引用的引用,C++不存在这种类型)。

如果再加入一个const,我就有了四种不同类型的引用类型。

lvalue   const lvalue   rvalue   const rvalue
---------------------------------------------------------              
X&              yes
const X&      yes      yes            yes      yes
X&&                                    yes
const X&&                              yes      yes


三、转移左值

1 unique_ptr<Shape> a(new Triangle);

2 unique_ptr<Shape> b(a); // an error

3 unique_ptr<Shape> c(std::move(a)); // okay

注意:C++11中使用unique_ptr来代替auto_ptr,但是它只接受右值(unique_ptr类有显示构造函数explicit unique_ptr(T* p = nullptr),以及转移构造函数unique_ptr(unique_ptr&&
source),另有一个转移赋值函数unique_ptr& operator=(unique_ptr&& source)),所以第二行出错。

基于安全的理由,具名的变量将永远不被认定为右值,即使它是被如此声明的;为了获得右值必须使用 std::move<T>()。

第三行之后,a不在拥有Triangle对象。 不过这没有关系,因为通过明确的写出std::move(a),我们很清楚我们的意图:亲爱的转移构造函数,你可以对a做任何想要做的事情来初始化c;我不要需要a了,对于a,您请自便。

std::move(some_lvalue)将左值转换为右值,使转移成为可能。

四、move语义

请参考文章开头的链接。

题外话:the rule of three

If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.

备注:C++ 98标准会在需要的时候自动生成三种特殊类型的成员函数:复制构造函数,赋值操作符和析构函数(默认的无参构造函数(如果定义了带参数的构造函数,也不会生成默认构造函数了)和一对取址操作符operator&也是自动生成的。)。C++
11标准增加了另外两种特殊成员函数:转移构造函数和转移赋值操作符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: