《Visual C++ 2012 开发权威指南》——2.2 Visual C++2012的语言新特性(2)

2.2 Visual C++2012的语言新特性(2)

Rvalue引用:N1610"Rvalues类对象的初始化的澄清"是早期尝试启用无rvalue引用move  语意。

这些新规则还没有完全实现VC11开发者预览中。

Rvalue引用v3.0添加自动生成的构造函数和移动赋值运算符在一定条件下的新规则。这不会进行中VC11,还将继续遵循的永远不会自动生成move构造函数/移动页本页的行为。

移动语义
Rvalue引用支持移动语义的实现,可以显著提高应用程序的性能。移动语义使能够调用资源编写代码(如动态分配的内存)来自对象到另一个。移动语义工作,因为它可以使资源从一个程序不能在其他位置引用的临时对象。

若要实现移动语义,通常会提供一个移动构造函数和(可选)为移动赋值运算符(operator=)的类。数据源自动是rvalues构造的副本并分配操作利用移动语义。不同于默认复制构造函数,编译器不提供默认构造函数移动。

还可以重载普通函数和运算符利用移动语义。Visual C++2012介绍移动语义到标准模板库(STL)。例如,string类实现执行移动语义的操作。考虑连接几个字符串并将结果输出到的示例:

// string_concatenation.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;

int main()
{
  string s = string("h") +"e" +"ll" +"o";
  cout << s << endl;
}```
之前,每个调用operator+分配并返回新临时string对象(rvalue)。operator+不能追加一个字符串。因为它不知道源字符串是否是lvalue或rvalues。如果源字符串都是lvalue,它们在程序中可能在其他位置引用并不能修改。使用rvalue引用,operator+可以修改rvalues,此过程不能在其他位置引用。因此,operator+现在可追加一个字符串到另一个。这样可以显著减少string类必须执行动态内存分配数。有关string类的更多信息,请参见basic_string的类。

移动语义还有助于,当编译器无法使用返回值优化(RVO)期间或命名返回值优化(NRVO)。在这些情况下,如果类型定义为移动语义,编译器将调用构造函数。有关命名的更多信息返回值优化,请参见Named Return Value Optimization in Visual C++2005。

更好地了解移动语义,请考虑插入元素的示例。vector对象。如果vector对象的容量会溢出,vector对象必须重新分配其元素的内存然后复制每个元素向另一个内存位置腾出空间。该插入的元素。在插入操作复制一个组件时,它将创建一个新元素,调用复制构造函数将前面的元素数据复制到新元素,然后销毁上一个元素。移动语义可以将对象直接,而不必执行开销很大的内存分配和复制操作。要在vector示例中的移动语义,可以编写移动数据移动构造函数对象到另一个。

有关移动语义的引入的更多信息。在Visual C++2012的STL中,请参见标准C++库参考。

完全转发
完全转发减少对重载函数的需要,并有助于避免转发问题。转发问题,可能会在泛型函数中采用引用编写,其参数和它通过(或向前)这些参数传递给另一个函数。例如,如果泛型函数采用类型const T&的参数,然后调用函数不能修改该参数的值。如果泛型函数采用类型T&的参数,则函数不能调用使用rvalue(如临时对象或整数值)。通常,解决此问题,必须提供采用T& 和const T& 其参数中的泛型函数的重载版本。因此,重载函数成指数增加带参数的数目。Rvalue引用编写接受任意参数前向到另一个功能的版本,就象另一个函数直接调用。

考虑声明四类型、W、X、Y和Z的示例。每个类型的构造函数采用const的不同组合,而非const lvalue引用作为其参数。

struct W
{
  W(int&, int&) {}
};

struct X
{
  X(const int&, int&) {}
};

struct Y
{
  Y(int&, const int&) {}
};

struct Z
{
  Z(const int&, const int&) {}
};```
假定需要编写生成对象的泛型函数。下面的示例演示一种此函数的编写:

template <typename T, typename A1, typename A2>
T* factory(A1& a1, A2& a2)
{
  return new T(a1, a2);
}```
下面的示例显示活动调用factory功能:

int a = 4, b = 5;
W* pw = factory(a, b);```
但是,下面的示例不包含有效调用factory功能,因为factory作为左值可以使用引用rvalues,可修改的作为其参数,但是,它调用:

Z* pz = factory<Z>(2, 2);
通常,解决此问题,必须创建factory函数的重载版本A& 和const A& 参数的每种组合。如下面的示例所示,Rvalue引用编写factory功能的版本,例如:

template <typename T, typename A1, typename A2>
T* factory(A1&& a1, A2&& a2)
{
  return new T(std::forward<A1>(a1), std::forward<A2>(a2));
}```
在向factory的参数函数,此示例使用rvalue引用。std:: 向前 功能的用途是向前工厂函数的参数传递给模板类的构造函数。

下面的示例演示使用修改后的factory函数创建W、X、Y和Z类的实例的main功能。修订了factory功能向前其参数(lvalue或rvalues)为相应的类构造函数。

int main()
{
  int a = 4, b = 5;
  W* pw = factory(a, b);
  X* px = factory(2, b);
  Y* py = factory(a, 2);
  Z* pz = factory(2, 2);

  delete pw;
  delete px;
  delete py;
  delete pz;
}```
Rvalue其他属性引用
可以重载函数采用了lvalue引用,并且rvalue引用。

通过重载函数采用const lvalue引用或rvalue引用,可以区分不能更改的对象中编写代码(lvalue)和可修改的临时值(rvalues)之间。可以传递给采用rvalue引用的功能的对象,除非该对象标记为const。下面的示例演示函数f,重载带有lvalue引用,并且有rvalue引用。main函数调用与有lvalue和rvalue的函数f。

// reference-overload.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;

// 使用内存资源的类
class MemoryBlock
{
  // 在此处为该类添加资源
};

void f(const MemoryBlock&)
{
  cout << "In f(const MemoryBlock&).This version cannot modify the parameter." << endl;
}

void f(MemoryBlock&&)/
{
  cout << "In f(MemoryBlock&&).This version can modify the parameter." << endl;
}

int main()
{
  MemoryBlock block;
  f(block);
  f(MemoryBlock());
}```
该示例产生下面的输出:

在此示例中,第一次调用f通过局部变量(左值)作为其参数。第二次调用f通过临时对象作为其参数。由于临时对象在程序中不能在其他位置引用,调用将为接受rvalue引用,可以自由修改对象f的重载版本。在左值和未命名的rvalue引用用作rvalue,编译器将一个名为rvalue引用。

在函数采用rvalue引用作为参数的写权限,该参数视为该函数体中的一个lvalue。因为命名对象可以由程序的几部分引用编译器将一个名为rvalue引用作为左值;允许程序的多个部件对该对象修改或移除资源是危险的。例如,因此,如果程序的多个部件尝试调用同一对象资源,因此,只有第一部分成功调用该资源。

下面的示例演示函数g,重载带有lvalue引用,并且有rvalue引用。函数f采用rvalue引用作为其参数(一个名为rvalue引用)并返回rvalue引用(未命名的rvalue引用)。在对g的调用从f,重载决策选择采用lvalue引用g的版本,因为f体将其参数用作左值。在对g的调用从main,重载决策选择采用rvalue引用g的版本,因为f返回rvalue引用。

// named-reference.cpp
// Compile with: /EHsc

include

using namespace std;

//使用内存资源的类.
class MemoryBlock
{
  //在此处为该类添加资源.
};

void g(const MemoryBlock&)
{
  cout << "In g(const MemoryBlock&)." << endl;
}

void g(MemoryBlock&&)
{
  cout << "In g(MemoryBlock&&)." << endl;
}

MemoryBlock&& f(MemoryBlock&& block)
{
  g(block);
  return block;
}

int main()
{
  g(f(MemoryBlock()));
}```
该示例产生下面的输出:

在此示例中,main函数传递rvalue到f。f体将其命名参数用作左值。从f的调用。g将参数传递给左值引用(g的第一个重载版本)。

可以将左值定义为rvalue引用。

STL std:: 移动功能可以转换为rvalue的对象对该对象的引用。或者,如下面的示例所示,可以使用static_cast关键字左值转换为rvalue引用,例如:

// cast-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;

//使用内存资源的类
class MemoryBlock
{
  //在此处为该类添加资源.
};

void g(const MemoryBlock&)
{
  cout << "In g(const MemoryBlock&)." << endl;
}

void g(MemoryBlock&&)
{
  cout << "In g(MemoryBlock&&)." << endl;
}

int main()
{
  MemoryBlock block;
  g(block);
  g(static_cast<MemoryBlock&&>(block));
}```
该示例产生下面的输出:

函数模板推导出自己的模板参数类型然后使用引用折叠的规则。

类的方法常见的做法是传递函数模板(或向前)的参数到另一个函数。有必要知道的模板类型推导如何为采用rvalue引用的函数模板。

如果函数参数是rvalue,编译器推导参数是rvalue引用。例如,如果通过rvalue引用类型X对象为接受类型T&& 作为参数的模板函数,模板参数推导T是X。因此,参数具有类型X&&。如果函数参数是一个lvalue或const lvalue,编译器推断其类型是lvalue引用或const lvalue引用该类型。

下面的示例声明一个结构模板随后专用它的各种引用类型。print_type_and_value函数采用rvalue引用作为其参数前向到S::print方法的适当的专用版本。main功能演示各种调用S::print方法。

// template-type-deduction.cpp
// Compile with: /EHsc

include

include

using namespace std;

template struct S;

// 下面分别制定S为
// lvalue reference (T&), const lvalue reference (const T&),
// rvalue reference (T&&), const rvalue reference (const T&&).
// 每个结构提供输出函数来输出每个结构的参数和类型.

template struct S {
  static void print(T& t)
  {
   cout << "print: " << t << endl;
  }
};

template struct S {
  static void print(const T& t)
  {
   cout << "print: " << t << endl;
  }
};

template struct S {
  static void print(T&& t)
  {
   cout << "print: " << t << endl;
  }
};

template struct S {
  static void print(const T&& t)
  {
   cout << "print: " << t << endl;
  }
};

template void print_type_and_value(T&& t)
{
  S::print(std::forward(t));
} 

// 此函数返回字符串 "fourth".
const string fourth() { return string("fourth"); }

int main()
{

  string s1("first");
  print_type_and_value(s1);

  const string s2("second");
  print_type_and_value(s2);

  // 下面的调用可以解析为:print_type_and_value(string&& t)
  print_type_and_value(string("third"));

  //下面的调用可以解析为:print_type_and_value(const string&& t)
  print_type_and_value(fourth());
}```
该示例产生下面的输出:

若要解决每次调用print_type_and_value函数,编译器先执行模板参数推导。会进行相应参数类型转换时,用模板参数的编译器将引用折叠的规则。例如,通过局部变量s1到print_type_and_value函数导致编译器生成下列函数签名:

print_type_and_value<string&>(string& && t)
编译器使用引用折叠的规则使该签名减少到以下操作:

print_type_and_value<string&>(string& t)
print_type_and_value功能的此版本向前然后它对S::print方法的正确的专用版本的参数。

下表总结了模板参数推导类型的引用折叠的规则:

模板参数推导是实现完全转发的元素。

时间: 2024-11-02 13:46:08

《Visual C++ 2012 开发权威指南》——2.2 Visual C++2012的语言新特性(2)的相关文章

《Visual C++ 2012 开发权威指南》——第2章 Visual C++2012语言新特性2.1 Visual C++2012的语言新特性(1)

第2章 Visual C++2012语言新特性 Visual C++ 2012 开发权威指南 有一种新的C++标准就有一种新版本的Visual C++,新的版本Visual C++将更加符合C++标准!在其发展过程中新的C++标准被(乐观)称为C++0x.它最后被发布在2011年,现在称为C++11. 对于Visual C++,它有三个不同版本的数字,有不同的内部版本和编译器版本(cl.exe和_MSC_VER宏-显示不同,因为我们C++编译器早在Visual C++中的"可视化").

《Visual C++ 2012 开发权威指南》——第1章 Visual Studio 2012的新特性1.1 如何安装Windows 8

第1章 Visual Studio 2012的新特性 Visual C++ 2012 开发权威指南 1.1 如何安装Windows 8 Windows 7进入市场已有3年,凭借其简洁.快速.个性和绚丽等特点,Windows 7号称微软历史上最成功的操作系统.作为微软下一代的主流操作系统Windows 8,在Windows 7速度和可靠性的基础上,对Windows操作系统进行了重塑.它提供全新的触控界面,是一种适用于新设备的新型Windows操作系统.现在市场上已有Windows 8 RP(Rel

《Visual C++ 2012 开发权威指南》导读

前言 Visual C++ 2012 开发权威指南2011年9月14日,微软发布了Windows 8开发者预览版,宣布兼容移动终端,这意味着Windows操作系统开始向更多平台迈进,包括平板电脑和PC.2012年2月微软又发布了Windows 8消费者预览版,可在平板电脑上使用. Windows 8大幅改变了以往的操作逻辑,对屏幕触控提供更佳的支持.Windows 8抛弃了旧版本Windows系统一直沿用的工具栏和"开始"菜单,采用了全新的Metro风格用户界面,各种应用程序.快捷方式

《Visual C++ 2012 开发权威指南》——2.3 Visual C++2012的语言新特性(3)

2.3 Visual C++2012的语言新特性(3) 在VC12(Visual C++2012),我们打算完全支持C++11标准库,但实施编译器功能可以自定义(另外,VC12不会完全实现C99标准库,已经通过引用纳入C++11标准库.注意本页和VC12已经有).这里是我们不断的变化的非详尽列表: 新头文件:......和. 进驻:根据需要由C++11,我们已经实现了emplace()/emplacefront()/emplace_back()/ emplace hint()/emplace_a

《Visual C++ 2012 开发权威指南》——1.2 如何安装Visual Studio 2012

1.2 如何安装Visual Studio 2012 为了在Visual Studio 2012开发环境中进行C++应用程序的开发,我们还需要安装Visual Studio 2012.由于visual Studio 2012在Windows 8系统中的兼容性和运行效果比在Windows 7系统中好,故我们选择在Windows 8系统中安装Visual Studio 2012.下面介绍Windows 8系统下Visual Studio 2012的安装过程. 一.下载Visual Studio 20

《Visual C++ 2012 开发权威指南》——1.3 Metro新特性

1.3 Metro新特性 Metro是微软在Windows Phone中正式引入的一种界面设计语言,也是Windows 8的主要界面显示风格."Windows 8"推出的一个专为触摸而设计的最新Metro风格界面,能向用户显示重要信息,这个界面同时支持鼠标和键盘,并应用于平板电脑.Metro风格界面设计风格优雅,可以令用户获取一个美观.快捷流畅的Metro风格的界面和大量可供使用的新应用程序.这些应用程序拥有远远超出图形设计范畴的新特性(一个平台).正如微软所展示的那样,通过出色的触控

图书-Anroid开发权威指南(第二版)pdf

问题描述 Anroid开发权威指南(第二版)pdf 谁有完整的<Anroid开发权威指南>的第二版? 网上只找到第一版pdf,求完整的新版

Android开发权威指南(第2版)新书发布(免费下载随书光盘内容,包括Android源代码)

光盘内容下载 光盘内容下载(新浪微盘) Android4.2.2(CM ROM)源代码下载 如果需要虚拟环境的,这里提供了ubuntu10.04 LTS版本,不需要CPU支持虚拟化(VirtualBox版[VirtualBox-4.2.10-84105]) Ubuntu10.04 VirtualBox版 分卷1 分卷2 分卷3 分卷4 分卷5 分卷6   用户名:root 秘密:12345678   <Android开发权威指南(第二版)>是畅销书<Android开发权威指南>的升

《Windows 8 开发权威指南:HTML5 和JavaScript卷》——1.2 如何安装Visual Studio 2012

1.2 如何安装Visual Studio 2012 Visual Studio 2012有四种版本:Ultimate.Preminum.Professional.Test Professional.这里我们以Ultimate版本在Windows 8操作系统上的安装过程为例进行说明. 下载安装文件的时候可以选择下列3个选项之一. 下载Web安装程序(vs_ultimate.exe). 下载产品布局(vs_ultimatelayout.exe). 下载DVD5 ISO映像(VS11_ULT_CHS