zoukankan      html  css  js  c++  java
  • C++11新特性

      0、使用C++11新特性,编译时需指定-std=c++11。

      1、auto与decltype:自动类型推导。

      如auto x = 7;,则推导x是int类型的。auto在类型难以确切知道或难以表达时很有用:

    template<class T, class U>
    void compute(T t, U u)
    {
        // x的类型在事先难以确切知道
        auto x = t * u;
        cout << sizeof(x) << endl;
    }
    
    int main()
    {
        compute<int, int>(1, 1);    // 4
        compute<int, double>(1, 1.2);    // 8
    
        vector<int> vec = {1, 2, 3, 4};
        // “传统的”遍历方式
        // for (vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++)
        // 简洁写法
        // for (auto iter = vec.begin(); iter != vec.end(); iter++)
        // 这种情况下,还可以这样遍历
        // for (auto ele : vec)
    
        return 0;
    }

      auto的另一个好处是,使用它定义的变量都必须初始化。

      decltype操作符用于取得操作数类型。如下例:

    int main()
    {
        int i = 0;
        decltype(i) j = i;  // &i != &j
        decltype((i)) k = i;  // k为int &类型。&i == &k
    
        int a[10] = {10};
        decltype(a) b;  // b为数组类型。sizeof(b) == 40
    
        int c[3] = {1, 2, 3};
    //  decltype(c[1]) d; // d为引用类型。因为没有初始化而报错
    
        return 0;
    }

      2、std::enable_if

    template <bool Cond, class T = void> struct enable_if {};

      若Cond为true则enable_if::type被设置为T,否则enable_if::type未定义(会导致编译出错)。示例:

    #include <type_traits>
    
    // 用法一
    template <class T>
    typename std::enable_if<std::is_integral<T>::value, bool>::type // is_integral::value为true时enable_if::type被设置为bool
    is_odd (T i) {return bool(i % 2);}
    
    // 用法二
    template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
    bool is_even (T i) {return !bool(i % 2);}
    
    int main()
    {
        short int i = 1;
        std::cout << std::boolalpha;
        std::cout << "i is odd: " << is_odd(i) << std::endl;
        std::cout << "i is even: " << is_even(i) << std::endl;
    
        float f = 1.0;
        // std::cout << "f is odd: " << is_odd(f) << std::endl; // 编译出错
    
        return 0;
    }

      3、lambda表达式

      1)简介:一种描述函数对象的机制。它可以访问它所在作用域内的局部变量(如第二个例子)。

      2)示例:

    int main()
    {
        vector<int> v = {50, -10, 20, -30};
        // 根据绝对值排序。第三个参数即为lambda表达式/函数
        sort(v.begin(), v.end(), [](int a, int b) { return abs(a) < abs(b); });
    
        return 0;
    }
    int main()
    {
        vector<int> vec(8);
        int count = 0;
        // 最终vec的元素为0~7
        generate(vec.begin(), vec.end(), [&count]() { return count++; });
    
        return 0;
    }

      []部分称为“捕获”(capture)列表。

      [&count]表示lambda表达式以引用方式“捕获”count,可以修改它。改成[]会报错,因为若没有“捕获”count则不能访问它;改成[count](值方式“捕获”)也会报错,因为此时count是只读的。另外,[]表示不“捕获”任何变量,[&]表示以引用方式“捕获”所有(可“捕获”的)变量,[=]表示以值方式“捕获”所有(可“捕获”的)变量。

      4、std::function和std::bind

      bind和function标准函数对象定义在<functional>中。它们被用于处理函数和函数参数。bind接受一个函数(或函数对象等)作为参数,并产生一个函数对象。如下面两个例子:

    int f(int i, char c, double d) { /* ... */ }
    
    int g(int) { /* */ }
    double g(double) { /* */ }
    
    int main()
    {
        // _1是占位符。使用时要加上using namespace std::placeholders;
        // 参数的绑定也称为局部套用(Currying)
        auto ff = bind(f, _1, 'c', 1.2);
        // 相当于f(7, 'c', 1.2);
        int x = ff(7);
    
        // 参数“反转”
        auto frev = bind(f, _3, _2, _1);
        frev(1.2, 'c', 1);
    
        // bind重载函数时
        auto gg = bind((double(*)(double))g, _1);
    
        // 另一种形式:显式指定返回类型(在C++98中才能实现)
        auto f2 = bind<int>(f, 7, 'c', _1);
    
        return 0;
    }
    struct st
    {
        int foo(int) { /* */ }
        int operator()(int x, int y) const { return x * y; };
    };
    
    int main()
    {
        // 创建函数对象
        function<int(int x, int y)> f1 = st();  // 先创建st对象,再将其operator()函数赋值给f1。调用方式:f1(5, 3);
    
        vector<int> vec = {1, 3, 5, 7, 9};
        // 将函数对象作为参数。累乘。2是起始值,结果为1890
        cout << std::accumulate(vec.begin(), vec.end(), 2, f1) << endl;
        
        // 创建函数对象,“指向”成员函数,第一个参数为相应类对象的指针
        function<int(st *, int)> f2;
        f2 = &st::foo;
        
        st s;
        int v = f2(&s, 5);        // 调用s.foo(5)
        function<int(int)> ff = std::bind(f2, &s, _1);    // bind的返回值可以赋值给函数对象
        v = ff(5);                // 调用s.foo(5)
        
        return 0;
    }

      5、tuple:把各种不同类型元素组合起来的一种类型。它是pair类型的泛化。在概念上类似于C的struct,但它通过元素在tuple中的序号访问元素,而不是通过元素名。需要include <tuple>并使用std命名空间。

    int main()
    {
        // 创建tuple
        tuple<const char *, int> tp1 = make_tuple("hello world", 11);
        // 获取元素
        cout << get<0>(tp1) << "	" << get<1>(tp1) << endl;
    
        int i = 0;
        // tie:将多个变量“捆绑(tie)”成一个tuple 
    // 如果只想获取tuple的部分元素,可以借助ignore
    tie(std::ignore, i) = tp1; cout << i << endl; pair<const char *, float> p1 = make_pair("Hello C++11", 1.2f); // tuple_cat:连结多个tuple(或pair) tuple<const char *, int, const char *, float, int> tp2 = tuple_cat(tp1, p1, tie(i)); // tuple_size:获取tuple的元素个数(维数)
    cout << tuple_size<decltype(tp2)>::value << endl;
    return 0; }

      6、多线程相关

      1)std::thread

      2)std::atomic。需要包含<atomic>。另外,编译时需要加上-pthread选项

      atomic类型的对象“包含”了一个特定类型的值。atomic对象保证了从不同线程(同时)访问该值时不会引起数据竞争。以下是来自cplusplus的例子:

    std::atomic<bool> ready(false);
    std::atomic<bool> winner(false);
    
    void count(int id)
    {
        while (!ready) {}  // 等待开始“信号”
        for (int i = 0; i < 1000000; i++) {}   // 每个线程都会计数到100w
        // exchange():(原子地)读取并替换atomic对象包含的值,返回替换前的值
        // 如果某个线程的exchange操作返回false(在此之前还没有其他线程执行exchange操作),则它是第一个计数到100w的
        if (!winner.exchange(true)) 
        {
            std::cout << "thread #" << id << " won!
    ";
        }
    };
    
    int main()
    {
        std::vector<std::thread> threads;
        for (int i = 1; i <= 10; i++) 
            threads.push_back(std::thread(count, i));
    
        ready = true;  // 开始计数的“信号”
        for (auto &th : threads)
            th.join();
    
        return 0;
    }

      其他一些常用的函数:

      store():修改atomic对象包含的值;load():读取atomic对象包含的值;fetch_add():(原子地)在atomic对象包含的值上做加法(read-modify-write),并返回操作前的值。

      7、unordered_map

      关联容器。和map类似,但其元素不是基于key或value排序,而是根据key的哈希值分配到内部哈希表的不同桶中。使用key访问元素的平均时间复杂度为常数。

    #include <iostream>
    #include <string>
    #include <unordered_map>
    
    int main()
    {
        std::unordered_map<std::string, std::string> mymap = {
            {"house","maison"}, {"apple","pomme"}, {"tree","arbre"}, {"book","livre"},
            {"door","porte"}, {"grapefruit","pamplemousse"}
        };
    
        // 也可以这样遍历:for (auto &p : mymap)
        std::cout << "All elements: ";
        for (auto it = mymap.begin(); it != mymap.end(); it++)
            std::cout << "[" << it->first << ": " << it->second << "] ";
        std::cout << std::endl;
    
        // 此时mymap.bucket_count()为7
        for (unsigned i = 0; i < mymap.bucket_count(); i++)
        {
            std::cout << "bucket #" << i << " has " << mymap.bucket_size(i) << " elements, they are: ";
            // begin()和end()的另一种用法
            for (auto it = mymap.begin(i); it != mymap.end(i); it++)
            {
                std::cout << "[" << it -> first << ": " << it -> second << "] ";
            }
            std::cout << std::endl;
        }
    
        // 此时mymap.load_factor()为0.857143(即6/7)
        mymap.max_load_factor(0.5);
        // 由于此时load_factor > max_load_factor,故需要增加桶的数目,mymap.bucket_count()变为13
    
        std::unordered_map<std::string, std::string>::hasher fn = mymap.hash_function();
        // fn("this"): 2428694746313403453、fn("thin"): 18140520699013722149
    
        return 0;
    }
    [root@localhost ~]# ./a.out 
    All elements: [grapefruit: pamplemousse] [door: porte] [tree: arbre] [book: livre] [apple: pomme] [house: maison]
    bucket #0 has 1 elements, they are: [tree: arbre]
    bucket #1 has 2 elements, they are: [book: livre] [apple: pomme]
    bucket #2 has 1 elements, they are: [door: porte]
    bucket #3 has 0 elements, they are:
    bucket #4 has 1 elements, they are: [house: maison]
    bucket #5 has 0 elements, they are:
    bucket #6 has 1 elements, they are: [grapefruit: pamplemousse]

      常用函数说明:

      load_factor():返回unordered_map容器当前的负载因数(load factor)。负载因数=容器中元素的个数/桶的数目,即平均每个桶的元素个数。它会影响哈希表中发生冲突的可能性。

      max_load_factor():获取或设置load factor的最大值(默认为1.0)。

      bucket_count():返回容器中桶的数目。桶的数目直接影响容器哈希表的负载因数,因而也影响冲突的可能性。当负载因数大于max_load_factor时,容器会自动增加桶的数目(以减小负载因数),此过程会对元素重新计算哈希值(rehash)。

      bucket_size():返回桶中元素的个数(影响访问桶中特定元素的时间)。

      size():返回容器中元素的个数。

      bucket():通过key定位到元素在哪个桶中。

      hash_function():获取容器使用的哈希函数对象。

      8、final:用于修饰虚函数时,在派生类中将不可重写该函数;用于修饰类时,表示该类不可被继承。

    struct Base
    {
        virtual void foo();
    };
    
    struct A : Base
    {
        void foo() final;  // 将A::foo()声明为final
        void bar() final;  // 出错:非虚函数不可声明为final
    };
    
    struct B final : A  // 将B声明为final
    {
        void foo() override;  // 出错:因为A::foo()已经声明为final,不可被override
    };
    
    struct C : B  // 出错:B已经声明为final,不可被继承
    {
    };

      参考资料:

      http://www.stroustrup.com/C++11FAQ.html

      http://www.cplusplus.com

      http://en.cppreference.com/w/cpp/language/final

      http://segmentfault.com/a/1190000003004734?_ea=266751#articleHeader5

    不断学习中。。。

  • 相关阅读:
    [JavaScript]使用setTimeout减少多余事件
    Spring.NET教程(二)——环境搭建(基础篇) (转)
    IIS开启GZIP压缩效率对比及部署方法 (转)
    提高表格操作的十五款jQuery插件
    SQLServer和Oracle常用函数对比
    [hystar整理]Entity Framework 教程
    Remoting方法重载遇到的一个问题
    异变: input的背景background
    实时股票数据接口
    发现并解决ASP.NET内存耗尽(OOM),让服务器"永不重启"
  • 原文地址:https://www.cnblogs.com/hanerfan/p/4672165.html
Copyright © 2011-2022 走看看