Linux | c&cpp | Email | github | QQ群:425043908 关注本站

itarticle.cc

您现在的位置是:网站首页 -> 代码相关 文章内容

C++11语法新特性-itarticl.cc-IT技术类文章记录&分享

发布时间: 9年前代码相关 89人已围观返回

Bjarne Stroustrup(C++的创造者)最近评价C++11:”感觉像个新的语言“。

事实上,C++11核心已经发生了很重大的变化:

1. 支持Lambda表达式( lambda expressions)

2. 对象自动类型推导(automatic type deduction of objects)

3. 统一初始化语法(uniform initialization syntax)

4. 代理构造(delegating constructors)

5. deleted 和defaulted函数声明(deleted and defaulted function declarations)

6. 空指针(nullptr)

7. 右值引用(rvalue references)

8. ...

C++11的标准库也已经修订,使用了新的算法,新的容器类,原子操作,类型,

正则表达式,智能指针, async() 功能,及多线程库。


1. Lambda表达式(Lambda Expressions)

Lambda表达式允许你在本地定义函数,即在调用的地方定义,

从而消除函数对象产生的许多安全风险,Lambda表达式的格式如下:

[capture](parameters)->return-type {body}

[]里是函数调用的参数列表,表示一个Lambda表达式的开始,

让我们来看一个Lambda例子:

假 设你想计算某个字符串包含多少个大写字母,使用for_each()遍历一个char数组,

下面的Lambda表达式确定每个字母是否是大写字母,每当它 发现一个大写字母,

Lambda表达式给Uppercase加1,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<<" uppercase letters in: "<< s<

}

以上例子就好像你在一个函数调用内部定义了一个新的函数。[&Uppercase]中的“&”记号

意味着Lambda主体获得一个 Uppercase的引用,以便它能修改,如果没有这个特殊记号,

Uppercase将通过值传递,C++11 Lambda表达式也包括成员函数构造器。


2. 自动类型推导和声明类型(decltype)

在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 fucn(const vector&vi)

{

vector::const_iterator ci=vi.begin();

}

有了自动类型推导后,你可以这样声明:

auto ci=vi.begin(); // 哈哈,省事了

关 键字auto不是什么新生事物,我们早已认识,它实际上可以追溯到前ANSI C时代,

但是,C++11改变了它的含义,auto不再指定自动存储类型对象,相反,它声明的对象

类型是根据初始化代码推断而来的,C++11删除了 auto关键字的旧有含义以避免混淆。

注意了:auto已经不再是当年的auto了!

C++11提供了一个类似的机制捕捉对象或表达式的类型,新的操作符decltype需要一个

表达式,并返回它的类 型。

const vectorvi; typedef decltype (vi.begin()) CIT; CIT another_const_iterator;


3. 统一初始化语法(uniform initialization syntax)

C++至少有4个不同的初始化符号,有些存在重叠,

括号初始化语法如下:

std::string s("hello");

int m=int(); //default initialization

在某些情况下,你也可以使用“=”符号进行初始化:

std::string s="hello";

int x=5;

对于POD聚合,你还可以使用大括号:

int arr[4]={0,1,2,3};

struct tm today={0};

最后,构造函数使用成员进行初始化:

struct S {

int x;

S(): x(0) {}

};

显然,这么多种初始化方法会引起混乱,对新手来说就更痛苦了,更糟糕的是,

在C++03中,你不能初始化POD数组成员,POD数组使用new[]分配,

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 array initializer

};

对于容器,你可以和一长串的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 这和Java一样

public:

C();

};


4. 代理构造(delegating constructors)

在C++11中,构造函数可以调用类中的其它构造函数:

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<<"delegating ctor"<

构造函数#2,代理构造函数,调用目标构造函数#1。


5. deleted 和defaulted函数声明(deleted and defaulted function declarations)

一个结构体中的函数:

struct A {

A()=default; //C++11

virtual ~A()=default; //C++11

};

对于被称为defaulted的函数,“=default;”部分告诉编译器为函数生成默认实现。

Defaulted函数有两个好处:比手工实现更高效,让程序员摆脱了手工定义这些函数的麻烦事。

与defaulted函数相反的是deleted函数:

int func()=delete;

Deleted函数对防止对象复制很有用,回想一下C++自动为类声明一个拷贝构造函数和一个赋值操作符,

要禁用拷贝,声明这两个特殊的成员函数为=delete即可:

struct NoCopy {

NoCopy & operator =( const NoCopy & ) = delete;

NoCopy ( const NoCopy & ) = delete;

};

NoCopy a;

NoCopy b(a); //compilation error, copy ctor is deleted


6. 空指针(nullptr)

终于,C++有了一个指定空指针常量的关键字,nullptr取代了有错误倾向的NULL宏和0,

这两个空指针替代品已经使用很多年了,nullptr是一个强类型:

void f(int); //#1

void f(char *); //#2

//C++03

f(0); //which f is called? 0可能是int,也可能是空指针,调谁?

//C++11

f(nullptr) //unambiguous, calls #2 这下好了,空指针只能是nullptr。

nullptr适用于所有指针类别,包括函数指针和成员指针:

const char *pc=str.c_str(); //data pointers

if (pc!=nullptr)

cout<

int (A::*pmf)()=nullptr; //pointer to member function

void (*pmf)()=nullptr; //pointer to function


7. 右值引用(rvalue references)

C++03中的引用类型只能绑定左值,C++11引入了一种新的引用类型,叫做右值引用,

右值引用可以绑定右值,例如,临时对象和字符串。

增加右值 引用的主要原因是移动语义(move semantics),与传统的复制不一样,

移动意味着目标对象偷窃了源对象的资源, 留下一个状态为“空”的源对象。

在某些情况下,复制 一个对象既代价高又没有必要,这时可以用一个移动操作代替。

如果你想评估移动语义(move semantics)带来的性能收益,可以考虑字符串交换,

一个幼稚的实现如下:

void naiveswap(string &a, string & b)

、 {

string temp = a;

a=b;

b=temp;

}

这样的代价很高,复制字符串必须分配原始内存,将字符从源拷贝到目标。

相反,移动字符串仅仅是交换两个数据成员,不用分配内存,拷贝char数组和删除内存:

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&&); //move assignment operator

};

C++11标准库广泛的使用了移动语义,许多算法和容器都为移动做了优化。

发布时间: 9年前代码相关89人已围观返回回到顶端

很赞哦! (1)

文章评论

  • 请先说点什么
    热门评论
    88人参与,0条评论

站点信息

  • 建站时间:2016-04-01
  • 文章统计:728条
  • 文章评论:82条
  • QQ群二维码:扫描二维码,互相交流