zoukankan      html  css  js  c++  java
  • 使用C++11的一点总结

          C++11已不是新鲜技术,但对于我来说,工作中用得还不够多(前东家长时间使用gcc3.4.5,虽然去年升了4.8.2,但旧模块维护还是3.4.5居多;新东家用的是4.4.6,不能完整支持C++11,而且有内部有基础库早已支持了C++11 STL的部分功能),再加上自己的练习也写得少,了解仅是几点简单的皮毛,这里对C++11学习总结一番,期望对他人以及未来的我有点技术知识索引上的帮助。
         首先,wiki是最全面的:https://en.wikipedia.org/wiki/C%2B%2B11,这是C++完整的新功能,个人使用的编译器可能不完整支持,可以看这个编译器+版本对C++1X的支持情况:http://en.cppreference.com/w/cpp/compiler_support
         然后,看英文不够快,找一篇看起来比较全的中文总结(不全,还是要看wiki):http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html

    一、新特性简介

    C++11之前被称为C++0x,因为原本计划在2010年发布,所以之前一些编译器使用C++11的编译参数是:-std=c++0x,后面使用:-std=c++11。C++11 设计的核心是:少改动语言,多改动基础库。
    改动涉及到这几点:支持多线程编程(增加了thread库)、加强泛型编程(增加了hash容器、任意多个元素的tuple、bind函数、lambda函数)、统一初始化(以花括号调用构造函数)、性能(右值引用和move),其它stl库(正则表达式、原子操作库),另外还有一些语法糖的支持,如:default、delete定义(可以在派生类中delete掉基类的public函数),裸字符串的定义、类非静态成员变量直接赋值、nullptr、支持连续两个右尖括号、后置返回类型、Range-based的for循环、构造函数可以调用另一个构造函数、override关键字用于发现虚函数的覆盖错误、string literal.......。

    二、部分常用新特性库

    挑选几个常用的记录如下

    1、统一初始化

     之前,我想初始化一个放着map对象的容器,需要这样子:
    std::vector<std::map<std::string, std::string> > a;
    std::map<std::string, std::string> tmp;
    tmp.insert(std::make_pair("1", "2"));
    a.push_back(tmp);
    现在,我可以直接用大括号:
    std::vector<std::map<std::string, std::string>> a{ { { "1", "2" } } }
    注: 部分统一初始化要到gcc4.7之后才支持。

    2、函数绑定和lambda

    函数绑定是基础库支持的,把一个函数转换为一个对象,在异步编程上用的很多(回调函数bind成一个对象,然后把对象交给异步工作完成的通知者,由它触发异步回调调用)。
    lambda语法,则可以跟标准库的算法配合使用,或者跟bind一起用在异步编程上。
    eg1: bind
    class Work {
    public:
     void do_work() {
        std::cout << "do work" << std::endl;
      }
    };
    int main() {
        Work work;
        auto bar = std::bind(&Work::do_work, &work);
        bar();
    }
    eg2:清除字符串中的'a'字符:
    std::string tmp = "abcdefgdaaa";
    tmp.erase(std::remove_if(tmp.begin(), tmp.end(), [](char x) {
            return x == 'a';
        }), tmp.end());
    std::cout << tmp << std::endl;
    lambda语法:
    [capture](parameters)->return-type->{body}
    [capture](parameters){body}
    [] // 没有定义任何变量。使用未定义变量会导致错误。
    [x, &y] // x 以传值方式传入(默认),y 以引用方式传入。
    [&] // 任何被使用到的外部变量皆隐式地以引用方式加以使用。
    [=] // 任何被使用到的外部变量皆隐式地以传值方式加以使用。
    [&, x] // x 显示地以传值方式加以使用。其余变量以引用方式加以使用。
    [=, &z] // z 显示地以引用方式加以使用。其余变量以传值方式加以使用。
    注:lambda需要gcc4.5之后才支持

    3、直接给类成员变量设置默认值

    Non-static data member initializers
    eg:
    class A {
    public:
        A () {}
        explicit A(int new_value) : value(new_value) {}
    
        int get() {
            return value;
        }
    private:
        int value = 5; // 支持直接写默认值
    };
    注:至少需要gcc4.7

    4、新增tuple类型

    tuple类型在传输多种类型组成的数据时,可以省去定义struct,而且可以有任意多的成员。
    eg:
    std::tuple<std::string, std::string, std::string, int, int> record = std::make_tuple("a", "b", "c", 100, 200);
    std::cout << std::get<0>(record) << std::endl;
    std::cout << std::get<4>(record) << std::endl;
    gcc4.4对tuple的支持不够完整(不用使用const 字符赋值给string),需要gcc4.7以上才完善。

    5、新增hash表

    std::unordered_set
    std::unordered_multiset
    std::unordered_map
    std::unordered_multimap
    查找性能比set、map的要快。

    6、新增多线程支持

    std::thread
    std::async
    std::promise,std::future,
    要特别说明下promise、future的概念:
    “主线程创建一个promise,将与promise关联的future交给新的线程,新线程等待从promise获取数据,主线程通过promise向期望设置值,新线程收到通知继续往下走。”
    这说明,promise/future是用于异步编程时,线程之间的同步的,有点像多线程编程下的event通知。
    eg:
    #include <iostream>
    #include <functional>
    #include <thread>
    #include <future>
    void show(std::future<int>& fut) {
        std::cout << "work thread:" << std::this_thread::get_id() << std::endl;
        int x = fut.get(); // 等待获取到结果
        std::cout << x << std::endl;
    }
    int main(){
        std::cout << "main thread:" << std::this_thread::get_id() << std::endl;
        std::promise<int> promise;
        std::future<int> future = promise.get_future();
        std::thread work_thread(show, std::ref(future));
        std::this_thread::sleep_for(std::chrono::seconds(3));
        promise.set_value(10);
        work_thread.join();
        return 0;
    }
    注:promise/future至少需要gcc4.7才支持
    扩展说明: 从上面的例子可以看到,标准库的promise/future不支持设置回调函数,需要自己通过get函数等待,这是异步调用者(主线程)主动的在等待通知,不像js可以通过.then函数设置回调通知函数,调用者可以被动的被调用。所以,当前不能做到彻底的异步编程(一个回调后面继续跟着回调)。但.then 函数已经在规划中,参见:
    "With .then, instead of waiting for the result, a continuation is “attached” to the asynchronous operation, which is invoked when the result is ready. "
    "do this, and when it is done, then do this, and when it is done, then do this..."
    有then函数的好处是,我们的代码可以实现彻底的异步,以上面的例子为例,我只要告诉future回调函数是xx,主线程就不用再等待,它可以去做别的,当工作完成的时候,工作线程主动的去触发回调函数xx的调用。
    另外,boost已经有then的功能,
    #include <iostream>
    #include <string>
    
    #define BOOST_THREAD_PROVIDES_FUTURE
    #define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
    
    #include <boost/thread/future.hpp>
    
    using namespace boost;
    
    int main() {
        future<int> f1 = async([]() { return 123; });
        future<std::string> f2 = f1.then([](future<int> f) {
            std::cout << f.get() << std::endl; // here .get() won't block
            return std::string("sgfsdfs");
        });
    }
    部分公司使用boost,或者从boost里借鉴future.then()的实现造了一个基础库,就可以在代码中实现 : do this, and when it is done, then do this, and when it is done, then do this ....

    7、其它

    (1)可以定义一个无需转义的字符串,如:std::string b = R"x(c:abc)" yy l)x";
    其中x(是一个标识符,x可以任意,最长16个字符。
    注意:Raw string literals至少需要gcc4.4
    (2)正则表达式库
    (3)构造函数委托
    (4)std::shared_ptr 智能指针
    (5)railing-return-type 后置返回类型
     
    本文所在:http://www.cnblogs.com/cswuyg/p/6220671.html
     
    学习参考:
     
  • 相关阅读:
    ReentrantLock重入锁
    Java对象序列化和反序列
    echarts踩坑笔记
    金融风控之贷款违约预测笔记
    go安装模块
    vasp计算轨道吸附
    html
    css/js 小技巧
    python 调用父类方法:super && 直接使用父类名
    python 多线程
  • 原文地址:https://www.cnblogs.com/cswuyg/p/6220671.html
Copyright © 2011-2022 走看看