UP | HOME

C++11 中的新特性

目录

自从 1998 年 C++ 标准通过后,历经 13 年,新的标准 C++11 才完善。 C++ 发明人 Bjarne Stroustrup 说“C++11 感觉象一门新语言”。实际上,变化的确很大。不过,最初实现垃圾回收的 (GC) 的愿望仍然没有在新标准中体现。

核心语言特性变化分述如后,更多的参见 C++11 FAQ中文版

Lambda 表达式

基本形式:

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

假如想计算字符串的大写字母个数,可用如下代码:

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<<endl;
}

自动类型推导和 decltype

以 C++11 中可以不用指定对象类型即可声明一个对象,例如:

auto x = 0;   // X 为 int 型,因为 0 属于 int 类型
auto c = 'a'; // char
auto d = 0.5; // double
auto national_debt = 14400000000000LL; // long long

当对象类型很冗长,或者是自动生成的 (如在模版中) 对象,比如:

void func(const vector<int> &vi) {
  vector<int>::const_iterator ci=vi.begin();
}

可以将 iterator 声明改为:

auto ci = vi.begin();

C++11 中提供了一种方法来返回对象或表达式的类型,即新的运算符 decltype:

const vector<int> vi;
typedef decltype (vi.begin()) CIT;
CIT another_const_iterator;

统一的初始化语法

C++ 至少有四种初始化表达方式,有些是相互重叠的。

参数的初始化象这样:

std::string s("hello");
int m=int(); //default initialization

也可以使用 = 达到同样的目的:

std::string s="hello";
int x=5;

对于 POD aggregates, 可使用花括号:

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

最终,结构体使用成员初始化方法:

struct S {
  int x;
  S(): x(0) {}
};

方法丰富也容易混淆,这不仅仅是对初学者。在 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<string> 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
public:
  C();
};

deletedefault 函数

可以这种形式来声明函数:

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

这样的函数称为 默认函数, 其中 = default 部分告诉编译器要生成默认实现的函数。

与默认函数相反的是 禁用函数:

int func() = delete;

禁用函数可用于阻止对象拷贝等。比如:

struct NoCopy {
  NoCopy & operator =( const NoCopy & ) = delete;
  NoCopy ( const NoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //compilation error, copy ctor is deleted

空指针 nullptr

空指针常量 nullptr 替换了问题多多的 NULL 宏。空指针 nullptr 是强类型的:

void f(int); // #1
void f(char *);// #2
// C++03
f(0); // which f is called?
// C++11
f(nullptr) // unambiguous, calls #2

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

const char *pc = str.c_str(); // data pointers
if (pc!=nullptr)
  cout << pc << endl;
int (A::*pmf)() = nullptr; // pointer to member function
void (*pmf)() = nullptr; // pointer to function

构造函数委派

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"<<endl;} //#2 delegating
};

右值引用

旧版本中赋值语句的右边永不会改变,这样做数值交换时往往效率很低,比如:

void naiveswap(string &amp;a, string &amp;b) {
  string temp = a;
  a=b;
  b=temp;
}

在交换数据时如果只是拷贝指针,而不需要再进行内存分配,这会很高效。比如:

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);
}

C++11 中引入“右值引用” (R-value reference), 标识为:

typename &&

它实现了 move semantics 操作,与上述的拷贝指针操作类似,不再需要重新分配内存。 C++11 STL 中广泛使用了右值引用,很多算法和容器的性能都被优化。

STL 标准类库

线程库

线程类涉及两个部分内容:

  1. 多个线程在一个进程中共存的模型;
  2. 对线程之间的交互提供支持。

参考: Simpler Multithreading in C++0x

新的智能指针类

在 C++11 中,以前的 auto_ptr 用法被废弃,新引入了两个指针类:

  • shared_ptr – 单纯的引用计数指针。
  • unique_ptr – 取代 auto_ptr.

新的算法

定义了一些新的算法: all_of(), any_of(), none_of(). 例如,将判断函数 ispositive() 应用到列表的范围 [first,first+n] 中:

#include <algorithm>  // C++11 code
// 全部元素都是正的?
all_of(first, first+n, ispositive()); //false
// 至少有一个为正的?
any_of(first, first+n, ispositive());//true
// 一个正的都没有吗?
none_of(first, first+n, ispositive()); //false

新的 copy_n 算法。比如用 copy_n() 来拷贝数组中的 5 个元素到另一个中:

#include
int source[5]={0,12,34,50,80};
int target[5];
//copy 5 elements from source to target
copy_n(source,5,target);

新算法 iota() 可用于创建值递增的序列:给 *first 赋个初值,后序的每个元素逐个加一。比如:

include <numeric>
int  a[5] = {0};
char c[3] = {0};
iota(a, a+5, 10);  // 将 a 变为 {10,11,12,13,14}
iota(c, c+3, 'a'); // 将 c 变为 {'a','b','c'}

参考

版权所有 ©2015: Exaos Lee | Date: [2014-12-19 五] | Generated by Emacs 24.4.1 (Org mode 8.3.2), Validate, 88x31.png

comments powered by Disqus