c++11中几个有用的新特性

int32位 posted @ Nov 02, 2013 01:00:09 PM in c/cpp , 1607 阅读
转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!

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 构造函数,这能够免除大幅的内存配置。

 基于安全的理由,具名的参数将永远不被认定为右值,即使它是被如此声明的 ;为了获得右值必须使用 std::move<T>()。
 

右值引用主要使用 && 标记:

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

转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!
  • 无匹配
  • 无匹配
Avatar_small
λ 说:
2013年11月03日 22:14

C++ 新手路过…… && 可以完美取代 & 吗?

Avatar_small
./a.out 说:
2013年11月04日 12:44

@λ:
&& 是右值引用,即实参必须右值。如果有函数原型为int foo(int &&x); 则调用foo(5)是可以的,但若int x = 5; foo(x)则不可以。另外传递右值实现move语义能减少拷贝对象带来的开销,现在很多STL都针对右值进行了重写。 /* 我也是cpp菜菜 */

Avatar_small
λ 说:
2013年11月04日 13:30

@./a.out: 原来只能引用右值啊……我还以为左右值都可以传了。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter