UP | HOME

C++11 中的新特性

Table of Contents

自从 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'}
                            

参考

88x31.png

版权所有 ©2012-2018: Vivodo Lio | 日期: 2014-12-19 五 00:00

Generated by Emacs 25.3.1 (Org mode 9.1.7), Validate