c++11 特性

C++11标准是 ISO/IEC 14882:2011 - Information technology – Programming languages – C++ 的简称。 C++11标准由国际标准化组织(ISO)和国际电工委员会(IEC)旗下的C++标准委员会(ISO/IEC JTC1/SC22/WG21)于2011年8月12日公布,并于2011年9月出版。2012年2月28日的国际标准草案(N3376)是最接近于C++11标准的草案(仅编辑上的修正)。此次标准为C++98发布后13年来第一次重大修正。

官方链接 https://en.cppreference.com/w/cpp/11

c++11 特性

1. 自动类型推导 auto & decltype

// 自动类型推导
std::map<std::string, std::string> m;
auto it = m.find("hello"); 

// decltype
auto i = 0;
decltype(i * 1.0) j; // typeid(j).name(): d

2. 左值,右值,移动语义,完美转发

  • 左值:带地址的值,可访问
  • 右值:
    • 纯右值:寄存器值,常量等不含内存地址的值
    • 将亡值:内存地址不可见的值,如函数返回值临时变量
  • RVO 返回值优化
    • 函数返回本地结构体变量等复杂数据,此时赋值会涉及多次拷贝
    • 返回值优化可以替换本地变量地址为外部地址,实现无拷贝赋值
    class A {
        std::string _name;
    public:
        A() {
            std::cout << "construct 0" << std::endl;
        }
        explicit A(const std::string& name) {
            std::cout << "construct 1" << std::endl;
            _name = name;
        }

        A(const A& a) {
            std::cout << "copy construct" << std::endl;
            _name = a._name;
        }

        A& operator=(const A& a) {
            std::cout << "operator =" << std::endl;
            _name = a._name;
            return *this;
        }
    };

    A getA(const std::string& name) {
        A a(name);
        std::cout << &a << std::endl;
        return a; // 返回本地变量
    }

    int main() {
        // 编译选项: -fno-elide-constructors
        // 将亡值赋值,一次构造,两次拷贝
        A a = getA("456");
        std::cout << &a << std::endl;

        // 引用强行续命, 一次构造一次拷贝
        const A& b = getA("123");  
        std::cout << &b << std::endl;

        // 去除编译选项
        // 返回值优化,仅一次构造
        A a = getA("456");
        std::cout << &a << std::endl;
    }
  • 移动语义 std:move()
    • 通过重载右值引用版本实现移动操作,减少内存复制
    class B {
        char* buf{};
        int size{};
    public:
        B() = delete;
        explicit B(int size) : size(size) {
            buf = new char[size];
        }

        B(const B& b) {
            std::cout << "copy" << std::endl;
            size = b.size;
            buf = new char[b.size];
            memcpy(buf, b.buf, b.size);
        }

        // 移动构造,无需分配新空间
        B(B&& b)  noexcept {
            std::cout << "move" << std::endl;
            size = b.size;
            buf = b.buf;
            b.size = 0;
            b.buf = nullptr;
        }

        B& operator=(const B& b) {
            std::cout << "=copy" << std::endl;
            if (&b == this) {
                return *this;
            }
            // clear
            delete []buf;
            size = b.size;
            buf = new char[b.size];
            memcpy(buf, b.buf, b.size);
            return *this;
        }

        // 移动赋值, 直接复制指针
        B& operator=(B&& b)  noexcept {
            std::cout << "=move" << std::endl;
            if (&b == this) {
                return *this;
            }

            this->buf = b.buf;
            this->size = b.size;
            b.size = 0;
            b.buf = nullptr;
            return *this;
        }


        ~B() {
            delete []buf;
        }

        int len() const {
            return size;
        }
    };

    int main() {
        B x(5);
        B y = x;  // copy
        B z = std::move(x); // move

        B xx(6);
        y = xx;  // =copy
        z = std::move(xx); // =move

        z = B(8);  // =move
        B zz(B(10)); // move
        return 0;
    }
  • 完美转发 std::forward()
    • 右值引用传入函数为左值,下游调用若需要右值,需要完美转发
    template<typename T>
    void lr_test(T&) {
        std::cout << "lvalue" << std::endl;
    }

    template<typename T>
    void lr_test(T&&) {
        std::cout << "rvalue" << std::endl;
    }

    template<typename T>
    void lr_normal(T&& a) {
        // 分配栈空间给a, 此时a 是语义右值,实质左值
        lr_test(a);  // 直接调用,传入左值
    }

    template<typename T>
    void lr_normal(T& a) {
        lr_test(a);
    }

    template<typename T>
    void lr_forward(T&& t) {
        lr_test(std::forward<T>(t));
    }

    int main() {
        int i = 0;
        lr_normal(1);  //rvalue -> lvalue
        lr_normal(i);  // lvalue

        lr_forward(1);  // rvalue
        lr_forward(i);  // lvalue
    }

3. 列表初始化

auto l = {"a", "b", "c"};
for (const auto& item : l) {
    std::cout << item << std::endl;
}

4. std::function 与 lambda表达式

  • std::bind, 绑定参数, 生成新的std::function
    // placeholders::_x 参数占位符
    auto minus = [](int i, int j) ->int {return i-j;};
    auto minus_by_five = std::bind(minus, 5, std::placeholders::_1);
    auto minus_eight = std::bind(minus, std::placeholders::_1, 8);

    std::cout << minus_by_five(10) << std::endl;
    std::cout << minus_eight(16) << std::endl;
    // bind object,函数地址, 对象地址
    auto f = std::bind(&B::len, &zz);
    std::cout << f() << std::endl;
  • lambda
    // base function, lambda
    std::function<void()> f = []() {/* statments */}
  • 变量捕获: 值捕获, 引用捕获
    auto o = 0;
    auto n = 1;
    auto fx = [o, &n]() {
        n = 100;  // change
        return o;  // readonly
    };
    std::cout << n << "," << o << std::endl;
    std::cout << fx() << std::endl;
    std::cout << n << "," << o << std::endl;

5. template 优化 » 问题

// >> 模版参数优化 
std::map<std::string, std::list<std::string>> list; // invalid before c++11 

6. 并发支持

  • std::thread 线程
  • std::mutex 互斥量
  • std::atomic 原子变量
  • std::condition 条件变量
  • std::future
  • std::async
  • std::promise
  • std::packaged_task

7. for range 循环

auto l = {1,2,3};
for (const auto&i : l) {
    // do something with i
}

8. 委托构造

class A{
std::string _name;
public:
    explicit A(const std::string& name) : _name(name) {}
}

class B:public A {
    // 子类委托父类构造
    explicit B(const std::string& name) :A(name) {}
}

9. nullptr 与 nullptr_t

    char* buf = NULL; // before c++11
    char* buf = nullptr; // after c++11

10. final, override 关键字

  • final 类禁止继承, final 方法禁止重写
  • override 重写 virtual方法
class C final {};  // can not extend

class D {
public:
    virtual void say() {}
    virtual void play() final {} // cannot override
};

class E: public D {
    void say() override {}  // override
//    void play() override {} // error
};

11. explicit 构造禁止隐式转换

  • 建议使用 explicit 修饰单参数构造函数避免隐式转换
class F {
    int data;
public:
    F(int d) : data(d) {}
};

class G {
    int data;
public:
    explicit G(int d) : data(d) {}
};

int main() {
    F f(1);
    G g(1);

    F f2 = 1; //ok
//    G g2 = 1; //nok
    return 0;
}

12. const, constexpr编译期常量

  • const 修饰变量为不可变变量(仅修饰作用,一些原本可变更的可用通过类型转换改变其值
  • constexpr: 编译期便确定的常量,编译阶段可以使用,运行期不可变

13. enum class

  • 强类型enum

14. union POD 扩展

  • union 不仅支持POD, 也支持普通对象了

15. sizeof(class::member)

  • sizeof 操作符支持查看对象成员的大小

16. static_assert 编译期断言

  • 编译期断言,断言失败编译失败

17. 自定义字面量

  • 通过 operator"" 自定义含unsigned long long 的字面量
constexpr mytype operator"" _mytype(uint64_t i) {
    return mytype(i);
}

18. 内存对齐

  • alignof
  • alignas

19. thread_local 线程变量

  • thread_local 修饰的变量为线程内部变量,每个线程有自己的拷贝

20. 数据类型 long long, char16_t, char32_t

  • 新增数据类型 long long, char16_t, char32_t

21. 随机数

std::random

22. 正则表达式

  • std:regex, 支持常用正则表达式, 有一些特性不支持

23. chrono

std::chrono::duration 时间段 std::chrono::time_point 时间点 std::chrono::steady_clock 时钟 std::chrono::system_clock 时钟

24. 容器

  • std::array 固定大小的数组,支持越界检查
  • std::tuple 元组, std::pair 的扩展
  • std::unordered_set 无序集合, hash表
  • std::unordered_map 无序映射, hash表

25. 算法

  • all_of
  • any_of
  • none_of
  • find_if

26. 智能指针

  • std::shared_ptr
  • std::unique_ptr
  • std::weak_ptr