第18 章探讨 C++新标准 移动语义和右值引用

第18 章探讨 C++新标准 移动语义和右值引用

第18 章探讨 C++新标准 移动语义和右值引用


18.2 移动语义和右值引用

现在介绍本书前面未讨论的主题。C++11支持移动语义,这就提出了一些问题:什么是移动语义?
C++11如何支持它?为何需要移动语义?下面首先讨论第一个问。
18.2.1 为何需要移动语义
先来看 C++11之前的复制过程。假设有如下代码:

vectorsatring> vstri
// build up a vector of 20,000 strings, each of 1000 characters...
vector<string>vstr copyl(vstr);// make vstr copyi a copy of vstr

vector和 string 类都使用动态内存分配,因此它们必须定义使用某种 new 版本的复制构造函数。为初始化对象vstr_copyl,复制构造函数 vcctor将使用new给20000个sting对象分配内存,而每个string对象又将调用 suing的复制构造函数,该构造函数使用new为1000个字符分配内存。接下来,全部20000000 个字符都将从 vstr 控制的内存中复制到vstrcopy控制的内存中。这里的工作量很大,但只要妥当就行。但这确实妥当吗?有时候答案是否定的。例如,假设有一个函数,它返回一个vector对象:

vectorestring>allcaps(const veetorestring>6 vs)
{
   
vector<string> temp;// code that stores an all-uppercase version of vs in temp
return temp;
}

接下来,假设以下面这种方式使用它:

vector<string> vstr;// build up a vector of 20,000 strings, each of 1000 characters
veetor<string> vstr copyi(vstr};// #3
vectorestring>vstr copy2(allcaps{
   vstr)};// #2

从表面上看,语句#】和#2类似,它们都使用一个现有的对象初始化一个 vector对象。如果深入探索这些代码,将发现 allcaps()创建了对象tcmp,该对象管理着20000000个字符:vector和string的复制构造函数创建这 20000000个字符的副本,然后程序删除allcaps()返回的临时对象(迟钝的编译器甚至可能将temp复制给一个临时返回对象,删除temp,再删除临时返回对象)。这里的要点是,做了大量的无用功。考虑到临时对象被删除了,如果编译器将对数据的所有权直接转让给vstr_copy2,不是更好吗?也就是说,不将20000000个字符复制到新地方,再删除原来的字符,而将字符留在原来的地方,并将vstr_copy2与之相关联。这类似于在计算机中移动文件的情形:实际文件还留在原来的地方,而只修改记录。这种方法被称为移动语义(movesemantics)。有点悖论的是,移动语义实际上避免了移动原始数据,而只是修改了记录。
要实现移动语义,需要采取某种方式,让编译器知道什么时候需要复制,什么时候不需要。这就是右值引用发挥作用的地方。可定义两个构造函数。其中一个是常规复制构造函数,它使用const左值引用作为参数,这个引用关联到左值实参,如语句#1中的vstr;另一个是移动构造函数,它使用右值引用作为参数,该引用关联到右值实参,如语句#2中 allcaps(vstr)的返回值。复制构造函数可执行深复制,而移动构造函数只调整记录。在将所有权转移给新对象的过程中,移动构造函数可能修改其实参,这意味着右值引用参数不应是const。
18.2.2 一个移动示例
下面通过一个示例演示移动语义和右值引用的工作原理。程序清单 18.2定义并使用了 Uscless 类,这个类动态分配内存,并包含常规复制构造函数和移动构造雨数,其中移动构造函数使用了移动语义和右值引用。为演示流程,构造函数和析构函数都比较啰嗦,同时Useless类还使用了一个静态变量来跟踪对象数量。另外,省略了一些重要的方法,如赋值运算符。

程序清单18.2 useless.cpp

// useless.cpp -- an otherwise useless class with move semantics
#include <iostream>
using namespace std;

// interface
class Useless
{
   
private:
    int n;          // number of elements
    char * pc;      // pointer to data
    static int ct;  // number of objects
    void ShowObject() const;
public:
    Useless();
    explicit Useless(int k)<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值