C++0x

  • Post author:
  • Post category:其他


C++0x作为C++的下一个国际标准,已经在业界热炒多年。但是,尽管业界对那个新标准千呼万唤,她总是不愿意过早地来到我们面前。在最近一次CodeGuru对C++之父Bjarne Stroustrup博士的采访中,C++之父终于给我们带来了好新闻——C++0x的标准化工作已经接近尾声,C++0x呼之欲出。下面是整个采访过程的节选,我们可以通过那个访谈,掀起C++0x的盖头来,相识C++0x的最新进展,新的特性以及将来的计划。

当我在写程序的时候:运用C++的原则和实践经验,并假设我正在运用的编程语言是C++0x,但是,如果不运用C++0x的新特性那将是一件非常痛苦的事情。我可以十分肯定地预言,对于C++的培训者和教习者,C++0x将是上天的恩赐。C++0x对于对于一些好的编程技术和风格提供了大量的更有力的支持。比如,目前我们有一个普遍一致的初始化机制,目前我们都统一运用“{…}”操作符完成变量的初始化工作,并且不管我们在什么中央运用“{v}”初始化一个变量X,我们都会得到不异的成果。对于C++98中不一致的初始化形式,“=v”、“={v}”和“(v)”,那是一个非常大的改进。

Bjarne Stroustrup: 我们计划在2011年3月26日进止终究的技术投票。虽然其后还会进止正式的国家投票以及ISO官僚主义的迟延,但是我十分相信,我们会在2011年使那个官方的标准来到我们面前。

是的,那些主要的新特性都很好,但是C++程序员们所关心的那些很紧张的问题呢?

Bjarne Stroustrup: C++0x对于C++的改进是以许多小的语言特性的改进以及部分新特性的增加的形势出现的,并不是对C++革命性的更新。我猜想,许多改进对于大多数人而言并不是十分紧张的,但是会让C++变成一门更好的程序设计语言。但是那一点也并不会影响我的核心观点:C++0x的改进弥集地分布在C++语言的各个部分;它们在许多中央以多种形式改善我们的C++代码;并不像人们凡是理解的改进一样,被隔离成某一个独立的新增加的组件。更形象地说,我认为C++0x的改进就像我们获得了很多新的种类的砖块,那样我们可以构建很多以前无法轻紧构建的建筑,并且更加容易和灵活优雅。实际上,运用C++0x,我总是能够写出比运用C++98更加简单更加优雅的程序,并且,凡是也会有更高的性能。

当我们首先来看几个可以让C++程序员的生涯更加轻紧舒服的C++0x改进。考虑下面那段代码:


void




f(vector<pair<string,


int


>>& vp)

我们还可以应用Lambda表达式进一步简化那个例子:

4、最初,我运用初始器{“simple”}创建了一个键。在C++98中,我们只能够以那样的方法初始化一个变量而不能初始化一个函数参数。C++0x通过“{…}”操作符,提供了一致的初始化方法。

2、我定义了一个变量p但是并没有明确地指出它的数据类型,作为替代,我运用了auto作为其数据类型,那就意味着“运用初始器(initializer)的数据类型”,所以p的数据类型就是vector<pair<string,int>>::iterator。那将节省程序员编码以及调试可能出现的Bug的时间。那是C++0x最“老”的新特性,我在1983年就实现了那个特性,但是因为一些兼容性问题,那一特性一直没有被纳入C++标准。

3、局部结构体is_key被用作模板参数类型,可能你并没有注意到那一点,但是那样的用法在C++98中是非法的。

1、在“vector<pair<string,int>>”中,第一个“>”和第二个“>”之间并没有空格,我认为那是C++0x中最小的改进,但是却可以省去程序员们添加空格的繁琐。


{


struct


is_key {


string s;

bool


operator()(


const


pair<string,


int


>&p)

{


return


p.first == s;

}

};

auto p = find_if(vp.begin(), vp.end(),

is_key{



"simple"


});

// …

}


那段代码看起来并没有什么激动人心的新改进,但是我要指出个中有四个小特性是C++98所不具备的:


void




f(vector<pair<string,


int


>>& vp)

不幸的是,我们并没有从标准库的层次上为unicode提供完整的支持,并且我们应该记住,大多数程序库并应该也不能够被包含在标准库中。我的C++页面上有很多关于程序库,程序库收集以及程序库列表的链接,大约估计有超过10000个C++程序库(包括商业的和开源的)。但是问题的关键是,你必须找到合适的程序库并评估它们。

Danny Kalev: 在所有关于C++0x的核心特性以及库的改进中,C++0x为一个典型的C++程序员带来了哪些好东西?C++0x的哪些方面使您特别骄傲?最初,鉴于目前市面上还短少关于C++0x的相关教材和资料,对于程序员们教习和运用C++0x的新特性您有什么建议?

标准库中的vector有一个移动机关函数(move constructor),它可以担当一个右值并简单地直接将其转换为目标对象,而不是复制容器中的所有元素来完成对象的创建。那就表现函数的返回可以通过简单的少数几次赋值完成,而不再是通过更多的,比如一百万次,逐个复制元素来完成函数的返回。那样,我们无需再运用繁琐而危险的指针,引用,内存的申请和释放等。移动语义为我们传递大体积的对象提供了一个全新的完整的解决方案。特别地,它的实现也非常简单,并且使得对于数据的操作更加富有用率,比如两个矩阵的乘法操作:

▲C++0x提供了一个更高抽象层次的并止计算模型。那个并止计算模型基于异步地执止多个任务,而那些任务之间又是通过所谓的新闻缓冲(message buffer)进止通信的。

Bjarne Stroustrup: 我更经常听到抱怨是C++太灵活并且太大。新的语言每每是比较简单的,因为它还没有形成一个庞大的社区。所有语言都会随着时间的流逝而增长。当然,修改一门大型的,有悠长历史并已经被广泛运用的编程语言要比推倒一切重来困罕见多。但是,很多新语言都会短命。并且,对于真实世界的应用来说,那些新语言显得太过简单了。向C++中添加新的内容是非常苦难的,对于一个新特性的建议者来说,要让那个新特性获得担当的过程凡是也是漫长和痛苦的。但是,一旦那个新特性获得担当,它将会对很多人产生十分重大的影响。如果我不想影响整个世界,我完全可以通过填字游戏,写小说或者是设计一门好玩的编程语言来让自己的才智得到发挥。

▲哈希容器

▲移动语义以及移动语义在标准库中的应用。特别地,目前我们可以以传值的方法从函数返回一个体积比较大的对象。例如:

1

Matrix operator*(


const


Matrix&,


const


Matrix&);

我可以一直继续下去,但是那将是一个长长的列表,但是那也将我们引向了更有趣的第二个问题:人们应该如何教习和运用C++0x中的那些新特性?我正在写第四版的《C++编程语言》(4th edition of The C++ Programming Language),但是那还有很多工作要做,那将会花费超过一年的时间。我想一定有其他的技术作者正在写或者正打算写关于C++0x的书,但是专家们或者C++的初教者想要找到比较好的书以及技术参考资料,恐怕还要等一段时间。(译注:我正在写一本全面笼罩C++0x新特性的C++参考书《我的第一本C++书》,即将由华中科技大教出版社出版,敬请期待)幸运的是,目前已经有一些关于C++0x的早期技术资料了,比如我的C++0x FAQ,它提供了很多简短的例子,以展示C++0x的核心特性,标准库的改建以及其它目前可以运用特性。但是,我们还需要更多的FAQ以及在线文档。我们还需要一些成系统地表明如何运用C++0x的新特性从而更好地支持C++的开发的资料。基于那样的考虑,我们需要的应该是一本书。

1
2
3
4
5
6
7
8
9

class


Matrix {


double


* elem;


// 指向成员变量的指针

int


dim1, dim2;

public


:

Matrix(Matrix&& a)

:dim1(a.dim1), dim2(a.dim2), elem(a.elem)


// 移动数据

{ a.dim1=0; a.dim2=0; a.elem=nullptr; }


// 将原来的数据清空

// ….

};

1
2
3
4
5
6
7

vector<


int


> make_vec(


int


n)

{


vector<


int


> res;

for


(


int


i=0; i<n; ++i)

res[i] = rand_int(0,100000);

return


res;

}

1
2
3
4
5
6
7
8

vector<


double


> v = { 1,2,3,4};


// a user-defined type

double


a[] = { 1,2,3,4};


// an aggregate

int


f(


const


vector<


double


>&);

int


x = f({1,2,3,4});

auto p =


new


vector<


double


>{1,2,3,4};

struct


S {


double


a, b; };

S s1{1,2};


// has no constructor

complex<


double


> z { 1,2,};


// has constructor

Danny Kalev: C++0x的标准化过程进展如何?我们目前有多么接近那个新的C++标准?

在我们从C++0x的简化中获得好处之前,可能我们会经历那样一个黑暗的时期——很多人会通过列举C++0x的新的语法规则或者是孔乙己式地深究C++0x的语法细节来展示自己的“聪明才智”。实际上,那样做是有害的。

我们不能指视人们仅仅通过阅读就能对C++0x编程有一个很好的理解。人们必须在开发实践中真正地运用那些新特性。幸运的是,C++0x的很多新特性已经在很多编译器(例如,GCC和Microsoft Visual C++)中实现了。C++0x不是象牙塔中的科教研究,而是真实地来到了我们身边。!

Danny Kalev: 整体而言,你认为将右值引用添加到C++0x是值得的吗?除了性能的提升之外,一个典型的C++程序员还能从右值引用中获得什么其他的好处呢?比如更简洁的设计,更简单的算法等等?

Bjarne Stroustrup: 我觉得将右值引用加入C++0x,不仅仅是值得,而是非常值得。移动语义可以作为一个长期存在的问题——如何从函数中返回一个体积较大的数据结构——的解决方案。对于那个问题,移动语义给了我们一个显而非诚勿扰易见的,简单而高效的答案:直接将成果从函数中移动到目标位置;不需要复制成果;不需要在内存管理上玩什么技巧;不需要运用混乱的特殊用途的内存管理方案;不需要函数的调用者预先申请内存;不需要通过额外的参数进止值的传递;不需要任何形式的垃圾回收机制。我认为那是右值引用的两个应用中的最紧张的一个。它将影响我们运用C++进止开发的每一小我,并且会让我们的生涯变得更好。开玩笑地说,以前很多人都说“聪明的程序员才能运用C++”,目前,有了移动语义,不那么“聪明”的程序员也可以运用C++了。我们可以省掉我们的聪明了。

值得注意的是,写一个有关右值引用移动的操作凡是是一件非常简单的事情,它不像送火箭上天那么困难啦。

▲传统的“threads-and-locks”风格的系统级并止计算的类型安全得到了支持。和一个可以用于无锁(lock-free)编程的新的内存模型一起,它们将共同为C++程序员们编写更加高效,更具备可移植性的并止计算程序提供强有力的支持。

那就是整个移动机关函数的完整过程:移动数据并将原来的数据清空。有了它的帮助,我们甚至可以简单而高效地返回一个10000*10000的矩阵。

当然,对于程序库的开发者而言那也将是非常紧张的一天: 在程序库中,有很多中央可以运用移动语义以简化程序库的实现,并且在更多的中央,转发(右值引用的另外一个紧张应用)将有助于程序库的设计与实现。并且,移动语义和完美转发并不是只有专家才能掌握的高深技术,每一个C++程序员都可以运用它们来简化我们的程序,提高程序的性能。

Danny Kalev: 在一些C++0x新特性,诸如右值引用,Lambda表达式,的设计中有很多困难。一些攻讦者也声称,C++太老了并且不够灵活。那些抱怨能可有一定的道理?会不会在将来的某一天,你决定不再扩展和改进C++,转而运用一种新的编程语言代替?

▲一个新的正则表达式标准库组件

当然,我也曾经胡想过设计一门比C++更新的、更小的、更好的编程语言,但是,每当我看到那门新语言可以解决的问题,以及那门新语言可能产生的影响,我就觉得大多数通过一门新的编程语言可以解决的问题同样都可以通过改进C++及其标准库来获得解决。就对编程世界产生积极影响——至少对于我来说——而言,看起来比较繁琐的对C++的不断改进要比设计、实现和推广一门新的编程语言要好得多。

Danny Kalev: 关于对Unicode的支持,C++0x提供了char_16和char_32,以及u16string和u32string来支持UTF16和UTF32编码的字符串。但是,它们在标准库中的输入输出流中并没有得到支持。例如,标准库中没有所谓的u16cout或u32cout。我想知道的是,我们该如何运用char16_t字符串并将它们输出?

Bjarne Stroustrup: 显然,我们应该有支持unicode的输入输出流以及在标准库中的其他的扩展对unicode进止支持。标准委员会知道那样的需要,但是没人有足够的能力和时间来实现它。因此,不幸的是,那是C++中一个你不得不寻供第三方支持的中央。实际上有很多现有的程序库都可以很好地支持unicode,例如,可以用于构建网络应用以及互联网应用程序的Poco库(http://pocoproject.org/index.html)。另外,Microsoft Visual C++对Unicode也有很好的支持。


{


auto p = find_if(vp.begin(), vp.end(),

[](


const


pair<string,


int


>&p)

{


return


p.first==


"simple"


;

});

// …

}

Lambda表达式是对函数对象的定义和运用的一种简化。那边,我们运用Lambda表达式简单地表现了find_if()算法的谓语运用pair作为参数并将其第一个元素与“simple”进止比较。

Danny Kalev: 最初,兔年已经到了,能不能和我们分享一下你的新年愿视是什么呢?

Bjarne Stroustrup:

▲让C++0x成为一个正式的ISO标准

▲完成《C++编程语言》第四版的初稿

▲和我的外孙共度更多的美好时光

▲提出至少一个感爱好的新的技术观点