c++11标准带来的最显著变化(及为何该引起你的注意)
来源:互联网 发布:犀牛软件破解版下载 编辑:程序博客网 时间:2024/06/07 22:47
来源 :http://article.yeeyan.org/view/234235/250515
简介:自C++语言首次标准化以来,13年的时间过去了。前C++标准委员会成员, Danny Kalev,阐述该编程语言有何改进,及其它如何有助于写出更好代码。
Bjarne Stroustrup,c++首创人,最近表示:c++11“感觉象一种新语言——各部分彼此更协调了”。确实,核心c++11已发生显著的变化。它现在支持lambda表达式,对象的自动类型推定,统一的初始化语法,委托构造函数,函数声明显式指定可删除及显式指定缺省,空指针关键字,以及最重要的右值引用——一种特性:兆示着在如何预想和处置对象上的范式发生了转化。以上只是举例。
c++11标准库也获得修订,加入了新算法,新容器类,原子操作,type traits,正则表达式,新型灵巧指针,异步方法,当然还有多线程库。
新核心与库功能的完整清单点此跳转。
标准在1998年通过之后,两位会议委员曾预言下一代c++标准必将具备某种内置的废物回收器(缩写为GC),而且可能不会支持多线程,因为在可移植线程模型的定义上,所涉及的技术复杂度不确定。13年后,新的标准c++11接近完成。意外的是,GC缺席了,反倒具有了一种顶尖的线程库。
在本文当中,我试图阐述标准中最显著的变化,以及这其中究竟是怎么一回事。你会看到,线程库并非其唯一的变化。新标准基于专家数十载的努力,令c++更其妥贴可用。就如Rogers Cadenhead指出的那样:“如同迪斯科、Pet Rocks(译者注:某种过时的美国游戏),或是类如大龄奥运游泳选手一般,c++已经老气横秋,而新出标准相当地令人惊喜”。
首先,来看看有些什么突出的语言特性。
Lambda表达式 用Lambda表达式可实现在调用地点定义局部函数,这么一来,显著避免了因启用函数对象而面临的繁琐表达和安全上的风险。一条lambda表达式有如下形式:
[capture](parameters)->return-type {body}
在一个函数调用的参数表内出现的[]方括弧构造,以之标示出一个lambda表达式的存在。我们举例来看。
假定要对字符串容器内的大写字母进行计数。利用标准库函数for_each遍历字符组,而如下列出的lambda式子来测定每个字母是否为大写。每个大写字母,一旦找出,则lambda式子把变量Uppercase加一,该变量定义在lambda表达式之外。
int main()
{
char s[]="Hello World!";
int Uppercase = 0; //modified by the lambda
for_each(s, s+sizeof(s), [&Uppercase](char c) {
if (isupper(c))
Uppercase++;
});
cout<< Uppercase<<" uppercaseletters in: "<< s<<endl;< div="">
}
这个表达式看似如同置身于函数调用体内部的一种函数定义代码。用&符号引导的Uppercase表示lambda表达式需要获取一个对变量Uppercase的引用作为实参,藉此,便可以修改该变量。如果不要&符号,Uppercase则作值传递。c++11的lambda包含也着针对成员函数的构造设计。
自动类型推定和delcltype(译者注:类型宣告) 在标准c++03下,对象的声明里必须指定对象的类型。然而多种情形下,对象的声明含有一个初始化要素。标准c++11则利用这一点,在声明对象时,不必显式指定他们的类型:
auto x=0; //x has type int because 0 is int
auto c='a'; //char
auto d=0.5; //double
auto national_debt=14400000000000LL;//long long
在对象类型太冗长或是(模板情形下)自动生成时,自动类型推定在简化表达上起主导作用。
void func(const vector &vi)
{
vector::const_iterator ci=vi.begin();
}
象这样声明迭代子:
auto ci=vi.begin();
关键字auto 不是新货色;它可上溯至前ANSI C时代。而今,C++11修改了它的含义;auto不再意味着设定对象为自动存贮类型了。而是用于声明一个对象,且该对象的类型由对象的初始化表达式推定出来。
C++11提供一种类似机制来捕获对象或表达式的类型。新进操作符decltype接受一个表达式,“返回”该表达式的类型:
const vector vi;
typedef decltype (vi.begin()) CIT;
CIT another_const_iterator;
统一的初始化语法 c++至少具有四种不同的初始化表示法,部分是重叠的。
带括弧的初始化看起来象这样:
std::string s("hello");
int m=int(); //default initialization
也可以用 = 记号 来达成某些情形下的初始化目的:
std::string s="hello";
int x=5;
对于POD(Plain Old Data的缩写,这种类型具有C兼容特点)性质的集合体,可用大括弧:
int arr[4]={0,1,2,3};
struct tm today={0};
最后一种情况,构造函数则使用成员初始化(列表):
struct S {
int x;
S(): x(0) {}
};
存在初始化的多种变体是富含困扰的根源,不仅对生手来说是麻烦,高手也如此。更糟的是,c++03标准之下,给POD数组分配堆要使用new[]记号,且无法初始化这种情况下的POD数组成员。c++11清除了这种混乱,它启用了统一的大括弧记号:
class C
{
int a;
int b;
public: C(int i, int j);
};
C c {0,0}; //C++11 only. Equivalent to: C c(0,0);
int* a = new int[3] { 1, 2, 0 }; /C++11 only
class X
{
int a[4];
public: X() : a{1,2,3,4} {} //C++11, member arrayinitializer
};
针对容器来说,现在可以淘汰充斥着push_back方法的冗长代码了(译者注:有时会使用循环结构)。C++11允许直观地表示容器初始化:
// C++11 container initializer
vector vs={ "first", "second","third"};
map singers = { {"Lady Gaga", "+1 (212)555-7890"}, {"Beyonce Knowles", "+1 (212) 555-0987"}};
类似的,C++11 支持类的数据成员就地初始化:
class C{
int a=7; //C++11 only
public:
C();
};
显式指定删除及显式指定缺省的函数声明 具备如下函数形式:
struct A{
A()=default; //C++11
virtual ~A()=default; //C++11
};
称之为缺省的函数。“=default;”记号部分指示编译器生成函数的缺省实作体。缺省的函数有两处优势:其一,比手工实作出来的代码更有效率,其二,把程序员从手工定义那些函数所引发的琐细事务中解脱出来。
与缺省函数对应,也存在指定删除函数:
int func()=delete;
声明删除的函数在防止复制对象的方面尤其有用。C++类自动声明一个复制构造函数和一个赋值操作。要禁止这种默认行为,使用记号=delete:
struct NoCopy{
NoCopy & operator =( const NoCopy & ) =delete;
NoCopy ( const NoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //compilation error, copy ctor isdeleted
nullptr C++终于提供了一个关键字用于表示空指针常量。nullptr替代了有隐患的宏NULL和文字量0, 它们一直以来被当作空指针代用品,已行之有年。现在,nullptr具备了强类型的性质(译者注:c++的宗旨之一是作为一种强类型语言,参考《C++语言的设计与演化》):
void f(int); //#1
void f(char *);//#2
//C++03
f(0); //which f is called?
//C++11
f(nullptr) //unambiguous, calls #2
nullptr适用于所有指针类型,包括函数指针和类成员指针:
const char *pc=str.c_str(); //data pointers
if (pc!=nullptr)
cout<<pc<<endl;<div="">
int (A::*pmf)()=nullptr; //pointer to member function
void (*pmf)()=nullptr; //pointer to function
委托构造函数
构造函数可能要调用本类中的其它构造函数:
class M //C++11 delegating constructors
{
int x, y;
char *p;
public:
M(int v) : x(v), y(0), p(new char [MAX]) {} //#1 target
M(): M(0) {cout<<"delegatingctor"<<="" span="">
2号构造函数为委托者,由它调用目标:即1号构造函数。
右值引用在 C++03中,引用类型只能与左值绑定。 C++11引入了新的引用类型称为右值引用。右值引用能与右值相绑定,例如临时对象和文字量。
增加右值引用的首要因素在于体现移动语义。与传统的复制不同,移动是指目的对象占据源对象的资源为己有,而源对象失去对资源的隶属关系。在某些情形中,复制对象的开销太大且没有必要,移动操作是其合理的替代。为感受移动语义在效率上好处,我们来看一个字串交换的过程。试看如下精简后的代码:
void naiveswap(string &a, string & b)
{
string temp = a;
a=b;
b=temp;
}
这种开销是不合理的。复制整个串将引发堆分配,然后从源对象复制数据至目的地。相比而言,移动串只是交换数据成员(译者注:是地址),而不必引起内存分配,复制字符组和删除内存这一系列的动作开销:
void moveswapstr(string& empty, string & filled)
{
//pseudo code, but you get the idea
size_t sz=empty.size();
const char *p= empty.data();
//move filled's resources to empty
empty.setsize(filled.size());
empty.setdata(filled.data());
//filled becomes empty
filled.setsize(sz);
filled.setdata(p);
}
假定实现一个支持移动的类,可以这么声明移动构造函数和移动赋值操作符:
class Movable
{
Movable (Movable&&); //move constructor
Movable&& operator=(Movable&&); //moveassignment operator
};
C++11标准库广泛使用移动语义。许多算法和容器目前都享有移动语义带来的优化。
2003 年,以库技术报告1(TR1)的形式,使得C++经历了一场重大改观。 TR1含有新容器类型族unordered_set,unordered_map,unordered_multiset, unordered_multimap),以及数个新进功能:正则表达式, tuples(译者注:元组收纳器),函数对象封装器等等。伴随标准 C++11的出台,TR1也正式集成到C++标准之内,这意味着TR1一直以来所具备的全新库功能已经可用。这里列举一部分C++11的库功能:
线程库 毫无疑问,以编程员的角度看,最重大的改进在于并发主题。 C++11引入了线程类来表示执行线程,promises 和 futures(译者注:并发编程设计领域的术语,参考wiki)——指在并发环境中用于同步的对象,针对启动并发任务而设计的async()函数模板,及针对声明线程专有数据(thread-unique data )的存储类型thread_local。欲对c++11线程库进行一次快餐体验,请阅读 Anthony Williams撰写的《c++0x,更简明的多线程》(Simpler Multithreading in c++0x)。
新灵巧指针类 C++98只定义了一种灵巧指针类,auto_ptr,现在已过时。C++11 具备一些全新的灵巧指针类:shared_ptr,及最近才加入的unique_ptr。两者与其它标准库组件兼容,故此在标准容器内能够安全地保存这些灵巧指针,也能使用标准算法操作这些对象。
新算法C++11标准库定义了新的算法,即模拟集合论领域的操作符all_of(),any_of(),none_of()。下列代码清单里,对[first,first+n]所限定的范围内,使用谓词方法ispositive()遍历检查每个元素,并且采用all_of(),any_of(),none_of()方法,来测定该范围整体的性质。
#include
//C++11 code
//are all of the elements positive?
all_of(first, first+n, ispositive()); //false
//is there at least one positive element?
any_of(first, first+n, ispositive());//true
// are none of the elements positive?
none_of(first, first+n, ispositive()); //false
一类新型copy_n算法也出笼了。利用copy_n()复制含有5个成员的数组到另一数组,可说是小菜一碟。
#include
int source[5]={0,12,34,50,80};
int target[5];
//copy 5 elements from source to target
copy_n(source,5,target);
算法iota负责创建有限的递增值序列,通过向*first表示的第一子项指定初始值,那么该值则被施加前缀++操作,以生成后序数据。
include
int a[5]={0};
char c[3]={0};
iota(a, a+5, 10); //changes a to {10,11,12,13,14}
iota(c, c+3, 'a'); //{'a','b','c'}
C++11仍然缺少一些实用库,例如XML应用接口,sockets,图形用户界面,reflection——当然,还有合理的自动化废物回收器。新标准确实提供了大量新功能,使得C++更形可靠,高效(是滴,这是迄今为止最高效的!参见谷歌的benchmarktests),易于学习和使用。
是否这些C++11 下的变化似乎有点动静太那个猛啦,要淡定。费点时间,循序渐进地领会这些新变化。最终,你说不定会赞同 Stroustrup的表述: C++11的确感觉象种新语言——更好的那种。
</pc<<endl;<>
</endl;<>
- c++11标准带来的最显著变化(及为何该引起你的注意)
- HTML5会为你的生活带来怎样的变化
- direct10带来的什么变化
- 事件驱动带来的变化
- 你最需要注意的11条要点for C++[转]
- FPGA规范及该注意的地方
- Java语言的最显著的特点
- 你最该知道的事(活着)
- 你最该知道的事(职场)
- 你最该知道的事(高级)
- C/C++超级需要注意的容易引起的Bug
- 标准C/C++发展史以及支持该标准的编译器
- PHP7 的抽象语法树(AST)带来的变化
- 你最需要注意的11条要点for C++
- 你最需要注意的11条要点for C++
- 你最需要注意的11条要点for C++
- 你最需要注意的11条要点for C++
- 你最需要注意的11条要点for C++
- 游戏相关链接
- JAVA 代理模式(Proxy)
- Domino的java代理优化(移出jar包的配置)(jco)
- 能力要求
- jsp页面获取参数 执行sql查询数据库
- c++11标准带来的最显著变化(及为何该引起你的注意)
- mysql error 1129 错误
- 标准差(Standard Deviation) 和 标准误差(Standard Error)
- iOS SDK:iOS调试技巧
- vcredist_x86.exe
- Notes
- PKU-1077 Eight (八数码之双向BFS)
- 来自官方的 windows 7 快捷键大全
- XTP(ToolkitPro)-Syntax Edit Lex Schema Help