1、foreach语法
java python 等都有foreach语法用于遍历容器(数组也可以看成是一种容器), java 中只要对象是数组或者实现了Iterable接口就能使用foreach语法。在c++11标准中也增加了这个特性。如下:
vector<int> v = {1, 2,3,4}; set<int> s = {1,2,3,1,2,3}; int a[] = {1,2,3}; for (auto i : v) cout << i; cout << endl; for (auto i : a) cout << i; cout << endl; for (auto i : s) cout << i; cout << endl;
2、auto类型推导
在c语言中auto关键字表示声明为自动变量,这个auto关键字可有可无,因为默认就是自动变量。在c++11标准后去掉自动变量显式声明方法。而auto关键字依然使用,但意思不再表示自动变量,而表示类型推导,或者说类型占位符。它会由初始化代码推断真实变量类型,这主要的用处是减少程序员的负担,
vector<int> v = {1, 2, 3, 4}; for (std::vector<int>::const_iterator i = v.begin(); i != v.end(); i++) cout << *i << endl;
而c++11标准可以方便的写成:
vector<int> v = {1, 2, 3, 4}; for (auto i = v.begin(); i != v.end(); i++) cout << *i << endl;
3、空指针类型。
在c中用NULL表示空指针,它表示不指示任何对象。而NULL实际上就是0, 有时为了表明是指针类型,可以这样:
#define NULL ((void *)0)
在c++11标准中增加新的关键字nullptr表示空指针,这个可以避免被隐式转化为整型0.
4、容器初始化。
之前vector<int> v需要初始化1,2,3,4,5,需要逐一push_back,c++11标准可以直接这样:
vector<int> v = {1, 2, 3, 4, 5}; for (auto i : v) cout << i << endl;
当然其他容器也可以这样。
5、lambda表达式。
学过python的一定不陌生了,具体语法参见:http://en.cppreference.com/w/cpp/language/lambda 。如下一个例子:
auto p = [&count](set<int> v) { for (auto i : v) { cout << i << ' '; count++; } cout << endl << "count:" << count << endl;; }; vector<int> v = {1, 2, 3, 4, 5}; set<int> s = {1,1,1,2,2,2}; int count = 0; p(s); count = 0; p({1, 1, 2,3,3, 4, 5, 6, 6}); /* 会自动转化为set<int>类型 */ count = 0; p({1, 1,1,1, 1, 1, 1});
6、全局begin()、end()方法。
非成员方法begin() 和 end()方法加入到STL中,提高了代码一致性,并利于GP化。而且可以使用数组。如下:
int a[] = {1, 2, 3, 4, 5}; set<int> s = {1,1,2,2,3,3}; for (auto i = begin(a); i != end(a); i++) cout << *i << ' '; cout << endl; for (auto i = begin(s); i != end(s); i++) cout << *i << ' '; cout << endl;
7、右值引用。先看以下代码:
int bar(int &x) { x++; printf("%d\n", x); return x; } int main(int argc, char **argv) { bar(5); return 0; }
有什么语法错误呢?对的,上面的bar(5)传入的是一个常数,即试图右值引用,而右值是不允许修改的,所以bar必须声明为int bar(const int &x)才能传入常数字面值。左值是一个有名子的对象,而右值是一个没有名字的临时对象。c++11标准加入右值引用的语法,主要为了实现move语义,实现内存优化管理,减少不必要的深度拷贝开销。
深度拷贝会发生在当对象是以传值的方式传递。举例而言,std::vector<T> 是内部保存了 C-style 数组的一个包装,如果一个std::vector<T>的临时对象被建构或是从 函数返回,要将其存储只能通过生成新的std::vector<T>并且把该临时对象所有的数据复制进去。该临时对象和其拥有的内存会被摧毁。在 C++11,一个std::vector的 "move 构造函数" 对某个vector的右值引用可 以单纯地从右值复制其内部 C-style 数组的指针到新的 vector,然后留下空的右值。这个操作不需要数组的复制,而且空的临时对象的析构也不会摧毁内存。传回vector临时对象的函数不需要显式地传回std::vector<T>&&。如果vector没有 move 构造函数,那么复制构造函数将被调用,以const std::vector<T> &的正常形式。 如果它确实有 move 构造函数, 那么就会调用 move 构造函数,这能够免除大幅的内存配置。
右值引用主要使用 && 标记:
int foo(int &&x) { x ++; printf("%d\n", x); return x; } int main(int argc, char **argv) { foo(5); return 0; }
另外还有更多的c++11标准,参见维基百科:C++11
2013年11月03日 22:14
C++ 新手路过…… && 可以完美取代 & 吗?
2013年11月04日 12:44
@λ:
&& 是右值引用,即实参必须右值。如果有函数原型为int foo(int &&x); 则调用foo(5)是可以的,但若int x = 5; foo(x)则不可以。另外传递右值实现move语义能减少拷贝对象带来的开销,现在很多STL都针对右值进行了重写。 /* 我也是cpp菜菜 */
2013年11月04日 13:30
@./a.out: 原来只能引用右值啊……我还以为左右值都可以传了。