ZC Miao
Friday, August 22 2008
C++之父 Bjarne Stroustrup最经在接受 DevX的采访时,就即将在2009年提交的 C++0x 最终标准草案作出了一些评定。他将新的扩展分为了三类:1、并发(Concurrency) 2、库(Libraries) 3、语言(Languages)。他们是:
Concurrency:
- memory model supporting modern machine architectures
- Threading ABI
- atomic types
- mutexes and locks
- thread local storage
- asynchronous message exchange
Libraries:
- regex: regular expressions
- unordered_map, etc. (hash tables)
- smart pointers
- array: fixed-sized array
- improvements to containers based on new C++0x features
- tuples
- date and time (maybe)
- various library components to held library builders
Language:
- rvalue references (move semantics)
- static_assert: static assertions
- variadic templates
- strongly typed enumerations with scoped enumerators
- constexpr: generalized constant expressions
- control of alignment
- delegating and inheriting constructors
- auto: deducing a type from an initializer
- decltype: a way of using the type of an expression in a declaration
- control of defaults
- nullptr: a name for the null pointer
- a range-based for loop
- lambda functions
- raw string literals
- UTF8 literals
- concepts (a type system for template arguments)
- initializer lists and uniform initializations syntax and semantics
- in-class member initializers
完整的采访,请见 http://www.devx.com/SpecialReports/Article/38813/0/page/1
我这里简单的说一下
右值引用和移动语义(rvalue references, move semantics)
该特性比较晦涩,但用途很明确。
* 移动语义
考虑swap函数
template swap(T& a, T& b)
{
T tmp(a); // now we have two copies of a
a = b; // now we have two copies of b
b = tmp; // now we have two copies of tmp (aka a)
}
用C++0x 的rvalue references特性,代码可以这样写了
template swap(T& a, T& b)
{
T tmp(std::move(a)); // 移动构造:移动临时变量a的值来构造tmp
a = std::move(b); // 移动赋值:将变量b的值移动到a
b = std::move(tmp); // 移动赋值:将临时变量tmp的值移动到b
}
这里就增了一个新的构造/赋值语义,首先温习一下C++的拷贝构造和拷贝赋值:
A(const A& a);
A& operator=(const A& a);
按照C++标准,临时变量如上面的foo返回的变量可以作为拷贝语义的变量,但只能以const&类型传递进。由于这个限制,想要为vector创造移动的语义(将内部的指针转移到另外一个变量而不产生额外的销毁操作)就不可能了。因为你没法修改 a 的变量,也就没法让临时变量在析构的时候不销毁其拥有的数据。
所以有了rvalue refs, 这个新增的构造语义就是移动语义,分别是移动构造和移动赋值
A(A&& a);
A& operator=(A&& a);
对于vector,实现这两个操作的可能逻辑就是:对于移动构造,取得a的内部指针,并将其清0;对于移动赋值,交换对象和a的内部指针。
这样以来,最初的问题就解决了。
标准库提供了 std::move 通用模板函数为变量或函数创建这种语义环境,比如:
vector v1,v2;
v2 = v1; // 调用拷贝赋值
v2 = std::move(v1); //调用移动赋值
注意,如果t是不可拷贝类型,比如臭名昭著的smart_ptr,那么这里的拷贝赋值则根本没法使用,因为vector的每个变量都无法被拷贝,而移动构造赋值则可以正确被调用。这也就是smart_ptr臭名昭著的原因所在,他根本没法和 stl 库配合使用,当然值得庆幸的是,C++0x已经收录了全能的 shared_ptr 了。
* 参数转移
还有一个功能是参数转移,以及新的 std::forward 通用模板函数。
所谓参数转移就是一个模板函数将其参数转移给另一个函数,听上去很容易,但目前C++里有个很麻烦的问题。还是因为临时变量,为了能够同时传递临时变量和左值变量,必须为每个参数提供两个版本的重载,比如:
template
void foo(const T& t)
{
goo(t);
}
template
void foo(T& t)
{
goo(t);
}
如果有两个参数,就有4个版本,如果有三个参数,就有8个版本。有了右值引用事情就简单多了:
template
void foo(T&& t)
{
goo(std::forward(t));
}
另外配合另外一个C++0x特性“变长函数模板”,就可以完美的实现函数代理了。比如将所有foo(a, b ...)函数转移到调用goo(somevar, a, b, ...)。
所以总的来说,右值引用的出现是作为语言的一个重要的完备性补充:以前作为右值的临时变量传递给函数时只能拷贝或者转换为常左值引用(const lvalue reference),现在则可以使用右值引用来捕获传递临时变量了。 其直接的作用就是产生了新的构造/复制语义,和新的参数转移方法。
参考文档
阅读(1985) | 评论(0) | 转发(0) |