Visual Studio 中的新增 C++ 和 MFC 功能文档格式.docx
《Visual Studio 中的新增 C++ 和 MFC 功能文档格式.docx》由会员分享,可在线阅读,更多相关《Visual Studio 中的新增 C++ 和 MFC 功能文档格式.docx(21页珍藏版)》请在冰点文库上搜索。
v.end(),[x,y](intn){
returnx<
n&
&
n<
y;
}),
v.end());
第二行显示了该lambda表达式。
方括号(称为lambda引导)指示lambda表达式的定义。
此lambda采用整数n为参数,lambda生成的函数对象具有数据成员x和y。
若与一个等效的手写函数对象进行比较,可看到lambda的方便性和省时性:
classLambdaFunctor{
public:
LambdaFunctor(inta,intb):
m_a(a),m_b(b){}
booloperator()(intn)const{
returnm_a<
m_b;
}
private:
intm_a;
intm_b;
};
v.erase(remove_if(v.begin(),v.end(),
LambdaFunctor(x,y)),v.end());
auto关键字在C++中一直存在,但很少使用,因为它没有提供任何附加价值。
C++0x将此关键字的作用改为根据变量初始值设定项自动确定变量的类型。
auto可降低复杂性并帮助突出重要代码。
它还可避免类型不匹配和截断错误。
该关键字通过允许编写不太在意中间表达式类型的模板帮助而提高代码的通用性,并能有效处理lambda之类的未记录类型。
下面的代码演示auto如何帮您省去在循环访问向量的for循环中键入模板类型的麻烦:
vector<
int>
v;
for(autoi=v.begin();
i!
=v.end();
++i){
//code
}
Rvalue引用是C++0x中引入的一种新的引用类型,可帮助解决不必要的复制问题并实现完美转发。
当赋值语句的右侧是rvalue时,左侧对象可以从右侧对象窃取资源而不是进行单独分配,这样就可以实现move语义。
完美转发允许您只编写一个函数模板,该模板采用n个任意参数并以透明方式将它们转发给另一个任意函数。
参数的性质(modifiable、const、lvalue或rvalue)在此转发过程中被保留。
template<
typenameT1,typenameT2>
voidfunctionA(T1&
t1,T2&
t2){
functionB(std:
:
forward<
T1>
(t1),std:
T2>
(t2));
有关rvalue引用的详细解释超出了本文的范围。
有关详细信息,请查看MSDN文档。
Static_assert允许在编译时而不是执行时测试断言。
使用它可以触发包含易于阅读的错误消息的编译器错误。
Static_assert对于验证模板参数特别有用。
例如,编译以下代码将给出错误“错误C2338:
自定义断言:
n应小于5”:
intn>
structStructA{
static_assert(n<
5,"
customassert:
nshouldbelessthan5"
);
int_tmain(intargc,_TCHAR*argv[]){
StructA<
4>
s1;
6>
s2;
return0;
Nullptr为null指针增添了类型安全性,并且与rvalue引用密切相关。
宏NULL(定义为0)和文本0通常用作null指针。
到目前为止还没有什么问题,但此代码在C++0x中不能很好地运行,因为在完美转发中存在潜在问题。
因此,专门引入了nullptr关键字来避免完美转发函数中出现不为人知的失败。
Nullptr是一个nullptr_t类型的常量,可以转换为任意指针类型,但不能转换为int或char之类的其他类型。
除了在完美转发函数中使用外,nullptr还可在使用宏NULL作为null指针的任意位置使用。
但请注意:
编译器仍支持NULL,尚未用nullptr将其取代。
这主要是为了避免由于普遍存在的常常不合适的NULL使用而导致现有代码的失败。
但在将来,以前使用NULL的所有地方都应使用nullptr,NULL只被视为用于支持向后兼容性的功能。
最后,decltype允许编译器根据任意表达式推断函数的返回类型并使完美转发更为通用。
在过去的版本中,对于两个任意类型T1和T2,无法推断使用这两个类型的表达式的类型。
例如,decltype功能允许您声明具有模板参数的表达式(例如sum<
T1,T2>
())具有类型T1+T2。
标准库改进
标准C++库的大部分都已重新编写,以便利用新的C++0x语言功能并提高性能。
此外,还引入了许多新算法。
标准库充分利用rvalue引用来提高性能。
如向量和列表这样的类型现在有其自己的move构造函数和move赋值运算符。
向量重新分配通过选择move构造函数利用move语义,因此如果您的类型有move构造函数和move赋值运算符,库将自动选择使用它们。
现在,在构造对象时,可以在新的C++0x函数模板make_shared<
T>
的帮助下同时创建一个指向该对象的共享指针:
autosp=
make_shared<
map<
string,vector>
>
(args);
在VisualStudio2008中获得同样的功能须编写以下代码:
shared_ptr<
sp(newmap<
(args));
使用make_shared<
更方便(必须键入类型名称的次数减少)、更强大(因为指针和对象是同时创建的,避免了以往常见的未命名shared_ptr泄露)并且效率更高(执行一次动态内存分配而不是两次)。
库中现在包含一个新的更加安全的智能指针类型unique_ptr(已由rvalue引用启用)。
结果就是弃用了auto_ptr;
unique_ptr通过变得可移动但不可复制避免了auto_ptr的缺陷。
这允许您实现严格的所有权语义而不影响安全性。
它也适用于识别rvalue引用的VisualC++2010容器。
现在容器有了新的成员函数cbegin和cend,它们提供了一种不考虑容器类型而使用const_iterator进行检查的方式:
for(autoi=v.cbegin();
=v.cend();
//iisvector<
const_iterator
VisualStudio2010在标准库中增加了各种C++0x文章中建议的大多数算法。
标准库中现在提供了Dinkumware转换库的一个子集,因此可以轻松进行像UTF-8到UTF-16这样的转换。
标准库通过exception_ptr启用异常传播。
标头<
random>
中进行了许多更新。
此版本中有一个名为forward_list的单链表。
库具有标头<
system_error>
来改进诊断。
此外,上一版本中存在于命名空间std:
tr1中的许多TR1功能(如shared_ptr和regex)现在都纳入了标准库中的std命名空间。
并发编程改进
VisualStudio2010引入了并行计算平台,可帮助您快速编写高性能并行代码并避免不易发现的并发Bug。
这样可以避开以往与并发有关的常见问题。
并行计算平台有四个主要部分:
并发运行时(ConcRT)、并行模式库(PPL)、异步代理库以及并行调试和分析。
ConcRT是争用资源的多个并发组件中与操作系统对话并进行仲裁的最低软件层。
因为它是用户模式进程,所以在使用其协作性阻止机制时可以回收资源。
ConcRT能够感知局部性并避免在不同处理器之间切换任务。
它还使用Windows7用户模式计划(UMS),因此即使未使用协作性阻止机制,它也可以提升性能。
PPL提供了用于编写并行代码的模式。
如果一个计算可分解为多个可由函数或函数对象表示的子计算,则这些子计算中的每一个都可以表示为一个任务。
任务概念与问题域更加相近,这与线程不同,线程会使人想到硬件、操作系统、关键部分等从而让您远离问题域。
一项任务可与其他任务并行执行,而无论其他任务的目的是什么。
例如,对一个数组的两部分排序可由两个不同任务并行进行。
PPL包含并行类(task_handle、task_group和structured_task_group)、并行算法(parallel_invoke、parallel_for和parallel_for_each)、并行容器(combinable、concurrent_queue和concurrent_vector)以及识别ConcRT的同步基元(critical_section、event和reader_writer_lock),它们都将任务视为第一级概念。
PPL的所有组件都位于并发命名空间中。
使用任务组可以执行一组任务并等待所有任务完成。
因此,在排序示例中,分别处理数组两个部分的任务可以组成一个任务组。
您一定会看到这两项任务在wait成员函数调用末尾完成,如以下代码示例所示,此示例是一个使用并行任务和lambda编写的递归quicksort:
voidquicksort(vector<
iteratorfirst,
iteratorlast){
if(last-first<
2){return;
intpivot=*first;
automid1=partition(first,last,[=](intelem){
returnelem<
pivot;
});
automid2=partition(mid1,last,[=](intelem){
returnelem==pivot;
task_groupg;
g.run([=]{quicksort(first,mid1);
g.run([=]{quicksort(mid2,last);
g.wait();
使用由parallel_invoke算法启用的结构化任务组可对此进一步改进。
它使用2到10个函数对象,使用ConcRT提供的尽可能多的内核并行执行这些函数对象,并等待它们完成:
parallel_invoke(
[=]{quicksort(first,mid1);
},
[=]{quicksort(mid2,last);
});
这些任务中的每一个都可以创建多个子任务。
任务和执行线程之间的映射(以及对优化利用所有内核的保证)由ConcRT管理。
因此,将计算分解为尽可能多的任务有助于利用所有可用内核。
另一个有用的并行算法是parallel_for,它可以用于以并发方式循环访问索引:
parallel_for(first,last,functor);
parallel_for(first,last,step,functor);
这会使用每个索引并发调用函数对象,从第一个开始,到最后一个结束。
异步代理库为您提供一个基于数据流的编程模型,其中计算取决于变为可用的必需数据。
此库基于代理、消息块和消息传递函数的概念。
一个代理就是一个应用程序组件,它执行特定的计算并与其他代理异步通信以解决更大的计算问题。
代理之间的这种通信通过消息传递函数和消息块实现。
代理具有历经不同阶段的可观察的生命周期。
它们不用于通过PPL任务实现的精细并行特性。
代理在ConcRT的计划和资源管理组件上生成,可帮助您避免因在并发应用程序中使用共享内存而引发的问题。
不需要链接或重新分发任何其他组件就可利用这些模式。
ConcRT、PPL和异步代理库已在msvcr100.dll、msvcp100.dll和libcmt.lib/libcpmt.lib中随标准库一起实现。
PPL和异步代理库基本是纯标头实现。
VisualStudio调试器现在识别ConcRT,这样便于您调试并发问题,这与不支持高级并行概念的VisualStudio2008不同。
使用VisualStudio2010的并发探查器可以可视化并行应用程序的行为。
调试器具有新窗口,可以可视化应用程序及其调用堆栈中的所有任务的状态。
图1显示了“并行任务”和“并行堆栈”窗口。
图1“并行堆栈”和“并行任务”调试窗口
IntelliSense和设计时效率
VisualStudio2010中包含了全新的IntelliSense和浏览基础结构。
除了帮助调整和响应具有大型基本代码的项目,此基础结构改进还带来了一些新的设计时效率功能。
如实时错误报告和快速信息工具提示这样的IntelliSense功能基于新的编译器前端,即使代码文件正在修改中,该前端也能分析完整的转换单元以提供关于代码语义的丰富且准确的信息。
所有代码浏览功能(如类视图和类层次结构)现在都使用SQL数据库中存储的源代码信息,该数据库启用了索引功能并具有固定的内存占用量。
与以前的版本不同,VisualStudio2010IDE始终具有响应能力,当编译单元由于头文件发生更改而重新分析时,您不再需要等待。
IntelliSense实时错误报告(我们熟悉的红色波浪线)在浏览和编辑代码时显示编译器质量语法和语义错误。
将鼠标悬停在错误上可查看错误消息(请参见图2)。
错误列表窗口也会显示当前查看的文件中的错误以及编译单元其他位置的IntelliSense错误。
不必进行生成即可获得所有这些信息。
图2显示IntelliSense错误的实时错误报告
此外,在键入#include时会在下拉列表中显示相关包含文件的列表,此列表随您的键入而精简。
新的“定位到”(“编辑”|“定位到”或Ctrl+逗号)功能将帮助您更有效地搜索文件或符号。
此功能根据您键入的子串给出实时搜索结果,将您的输入字符串与任意项目中的符号和文件对照匹配(请参见图3)。
此功能还适用于C#和VisualBasic文件,并且可进行扩展。
图3使用“定位到”功能
调用层次结构(使用Ctrl+K、Ctrl+T或从右键单击菜单中调用)可以定位到从某一特定函数调用的所有函数,以及对特定函数进行调用的所有函数。
这是以前的VisualStudio版本中存在的“调用浏览器”功能的改进版本。
“调用层次结构”窗口组织得更好,对同一窗口中出现的任何函数同时提供调用来源和调用目标树。
请注意,虽然所有代码浏览功能都可用于纯C++和C++/CLI,但像实时错误报告和快速信息这样的IntelliSense相关功能在VisualStudio2010最终版中不可用于C++/CLI。
此版本中还对其他一些主要编辑器功能做出了改进。
例如,用于在整个解决方案中搜索对代码元素(类、类成员、函数等)的引用的“查找所有引用”功能现在更为灵活。
使用右键单击上下文菜单中的“解析结果”选项可进一步精简搜索结果。
非活动代码现在通过维护颜色设置(而不是成为灰色)保留语义信息。
图4显示了非活动代码虽然变暗,但仍显示不同颜色来传达语义信息。
图4非活动代码块保留颜色设置
除了上面介绍过的功能外,常规编辑器体验在VisualStudio2010中也得到了增强。
为消除混乱并提高可读性,新的基于WindowsPresentationFoundation(WPF)的IDE经过了重新设计。
像代码编辑器和设计视图这样的文档窗口现在可以浮动在主IDE窗口之外,并可在多个监视器中显示。
使用Ctrl键和鼠标滚轮可以轻松缩放代码编辑器窗口。
IDE还增强了可扩展性支持。
生成和项目系统
VisualStudio2010还在针对C++项目的生成系统和项目系统方面做出了重要改进。
最重要的更改是现在使用MSBuild生成C++项目。
MSBuild是可扩展的、基于XML的生成业务流程引擎,在以前的VisualStudio版本中已经用于C#和VisualBasic项目。
MSBuild现在是所有语言通用的Microsoft生成系统。
在生成实验室和各开发人员计算机上都可使用该系统。
C++生成过程现在按照MSBuild目标和任务文件定义,提高了可自定义性、可控性和透明性。
C++项目类型有了新的扩展名:
.vcxproj。
VisualStudio会自动将旧的.vcproj文件和解决方案升级为新格式。
还有一个命令行工具vcupgrade.exe用于从命令行升级单个项目。
过去,只能使用随您的当前VisualStudio版本提供的工具集(编译器和库等等)。
您必须等到能够迁移到新工具集,然后才能开始使用新的IDE。
VisualStudio2010允许您以多个工具集版本为目标进行生成,从而解决了这一问题。
例如,您可以将VisualC++9.0编译器和库作为目标,同时在VisualStudio2010中工作。
图5显示了属性页上的本机多定向设置。
图5以多个平台为目标的工具集
使用MSBuild大大增加了C++生成系统的可扩展性。
当默认生成系统不足以满足您的需求时,可以通过添加自己的工具或任意其他生成步骤扩展该系统。
MSBuild使用任务作为可执行代码的可重复使用单元来执行生成操作。
可以创建您自己的任务并通过在XML文件中定义它们来扩展生成系统。
MSBuild从这些XML文件动态生成任务。
通过向ImportBefore和ImportAfter文件夹中添加附加步骤的.props和.targets文件可扩展现有平台和工具集。
这对于要扩展现有生成系统的库及工具提供商特别有用。
您还可以定义自己的平台工具集。
此外,MSBuild还提供更好的诊断信息,使您可以更加轻松地调试生成问题,这还提高了增量生成的可靠性。
此外,您还可以使创建的生成系统与源代码管理和生成实验室关系更为密切,而对开发人员计算机配置依赖更少。
生成系统顶部的项目系统也利用MSBuild提供的灵活性和可扩展性。
项目系统了解MSBuild过程并允许VisualStudio以透明方式显示通过MSBuild提供的信息。
自定义项是可见的,并且可通过属性页进行配置。
您可以配置项目系统使用您自己的平台(如现有的x86或x64平台)或您自己的调试器。
使用属性页可以对组件进行编写和集成,使之动态更新依赖于上下文的属性的值。
使用VisualStudio2010项目系统甚至可以自编自定义UI来读写属性,而不必使用属性页。
更快的编译和更好的性能
除了到目前为止已经介绍的设计时体验改进之外,VisualStudio2010还通过多方面增强编译器后端的代码生成功能,提高了使用VisualC++编译器生成的应用程序的编译速度、质量和性能。
某些特定应用程序的性能取决于工作集。
通过此版本中进行的多项优化,x64体系结构的代码大小缩减了3%到10%,从而提高了此类应用程序的性能。
单指令多数据(SIMD)代码生成(对于游戏、音频、视频和图形开发人员非常重要)已经过优化,可以提高性能和代码质量。
所做改进包括打破错误依赖关系、向量化常量向量初始化以及通过更好地分配XMM寄存器消除多余的负载、存储和移动。
此外,还优化了__mm_set_**、__mm_setr_**和__mm_set1_**固有系列。
为改进性能,应使用链接时间代码生成(LTCG)和按配置优化(PGO)生成应用程序。
x64平台上的编译速度已通过优化x64代码生成而得到提高。
LTCG编译(为更好地优化推荐