《C++语言导学(第二版)》读书笔记


第1章 基础知识

  1. 为了使长字面常量更易读,可以使用单引号(’)作为数字分隔符。

    int n = 123'456'789;
  2. 对于带初始化的 if 语句,如果条件是检验变量是否为 0(或者 nullptr),可以省略条件的显示描述。

    vector<int> v;
    // 下面两个if语句意义相同
    if (auto n = v.size(); 0 != n) {}
    if (auto n = v.size()) {}

第2章 用户自定义类型

  1. 使用 variant 代替 union

    vector<variant<int, string>> vv = { "kibazen.cn", 8888 };
    for (const auto& v : vv) {
        if (holds_alternative<int>(v)) {
            cout << "int value with: " << get<int>(v) << endl;
        } else if (holds_alternative<string>(v)) {
            cout << "string value with: " << get<string>(v) << endl;
        }
    }
  2. 默认情况下,enum 只定义了赋值、初始化和比较(如 == 和 <)操作。但是枚举类型是一种用户自定义类型,所以可以为枚举类型定义别的运算符。

    // enum 和 enum class 都可以
    enum class Color {
        red,
        green,
        blue,
    };
    
    Color& operator++(Color& c) {
        switch (c) {
        case Color::red:
            return c = Color::green;
        case Color::green:
            return c = Color::blue;
        case Color::blue:
            return c = Color::red;
        }
    }

第3章 模块化

  1. 一个单独编译的 .cpp 文件(包括它使用 #include 包含的 .h 文件)称为一个 编译单元(translation unit)

  2. 头文件 include 和模块 module 的差异不仅是语言上的。

    • 一个模块只会编译一遍(而不是像头文件一样在使用它的每个编译单元中都编译一遍)。
    • 两个模块可以按任意顺序导入(import)而不会改变它们的含义。
    • 如果你讲一些东西导入一个模块中,则模块的使用者不会隐式获得这些东西的访问权(但也不会被它们所困扰):import 无传递性。
  3. 声明为 noexcept 的函数抛出异常时,程序会自动调用 terminate() 函数来终止整个程序。

  4. 结构化绑定。

    struct Info {
        int key;
        string value;
    };
    
    Info get_info()
    {
        return Info { 1, "k" };
    }
    
    auto [k, v] = get_info();
    
    map<int, string> m = { { 1, "k" } };
    for (const auto& [k, v] : m) {}

第4章 类

第5章 基本操作

  1. 右值引用的含义是,引用一个别人无法赋值的内容,所以我们可以安全地”窃取”它的值。

第6章 模板

  1. C++17中允许从构造函数参数中推断模板参数。

    pair p = { 1, 5.2 }; // pair<int, double>
    tuple t = { 1, 1.0, "a"s }; // tuple<int, double, string>
    vector vi = { 1, 2, 3 }; // vector<int>
    vector vc = { "a", "b", "c" }; // vector<const char*>
    vector vs = { "a"s, "b"s, "c"s }; // vector<string>
    template <typename T>
    class Vector {
    public:
        using value_type = T;
    
        Vector(initializer_list<T> l) { }
    
        template <typename Iter>
        Vector(Iter begin, Iter end) { }
    
        T* begin() const { return nullptr; }
        T* end() const { return nullptr; }
    };
    
    template <typename Iter>
    Vector(Iter, Iter) -> Vector<typename iterator_traits<Iter>::value_type>;
    
    Vector v1 { 1, 2, 3, 4, 5 }; // Vector<int>
    Vector v2(v1.begin(), v1.end()); // Vector<int>

    Class template argument deduction (CTAD) (since C++17)

第7章 概念和泛型编程

  1. 可变参数模板

    void print0()
    {
        cout << endl;
    }
    
    template <typename T, typename... Tail>
    void print0(T head, Tail... tail)
    {
        cout << head;
        print0(tail...);
    }
    
    template <typename T, typename... Tail>
    void print1(T head, Tail... tail)
    {
        cout << head;
        if constexpr (sizeof...(tail) > 0) {
            print1(tail...);
        } else {
            cout << endl;
        }
    }
    
    print0(1, "char", "string"s);
    print1(1, "char", "string"s);
  2. 表达式折叠

    template <typename ...T>
    void print2(T&&... args)
    {
        (cout << ... << args) << endl;
    }
    
    // (((cout << 1) << "char") << "string"s) << endl;
    print2(1, "char", "string"s);
    template <typename... T>
    auto sum0(T... v)
    {
        return (v + ... + 0);
    }
    
    // 右折叠:(1 + (2 + (3 + 0)))
    sum0(1, 2, 3);
    
    template <typename... T>
    auto sum1(T... v)
    {
        return (0 + ... + v);
    }
    
    // 左折叠:(((0 + 1) + 2) + 3)
    sum1(1, 2, 3);

第8章 标准库概览

第9章 字符串和正则表达式

第10章 输入输出

第11章 容器

  1. vector 的下标运算符增加范围检查功能。

    template <typename T>
    class Vec : public std::vector<T> {
    public:
        using vector<T>::vector; // 使用 vector 的构造函数(但名字是 Vec)
    
        T& operator[](int i)
        {
            return vector<T>::at(i);
        }
    
        const T& operator[](int i) const
        {
            return vector<T>::at(i);
        }
    };

第12章 算法

第13章 实用功能

  1. span 的使用

    void use(span<int> vi)
    {
        for (int v : vi) {
            cout << v << endl;
        }
    }
    int arr[100];
    use(arr);
    
    vector vi = {1,2,3};
    use({vi.begin(), vi.end()});
  2. 如果一个 tuple 中的某个元素的类型在 tuple 中是唯一的,可以通过其类型来获取它。

    tuple<int, string> t = { 1, "k"s };
    get<string>(t) = "m";
  3. pair 类似,只要 tuple 的元素支持赋值操作和比较操作,整个 tuple 就能进行赋值和比较。

  4. 标准库提供了三种类型来表达选择:

    • variant 用来表达一组指定选择中的一个。
    • optional 用来表达一个指定类型的值或者没有值。
    • any 用来表达一组不限数量的可选类型中的一个。
  5. 有状态的内存分配系列工具 pmr(polymorphic memory resources) 。

    pmr::synchronized_pool_resource pool;
    
    struct Event {
        pmr::vector<int> data = pmr::vector<int> {512,  &pool };
    };
    
    pmr::list<shared_ptr<Event>> q { &pool };
    
    void producer()
    {
        for (int n = 0; n != INT_MAX; ++n) {
            q.push_back(allocate_shared<Event, pmr::polymorphic_allocator<Event>>(&pool));
        }
    }

第14章 数值

  1. 标准库中数学函数报告错误的方式由头文件 #include <cmath> 中宏 math_errhandling 的值决定,其值等于 MATH_ERRNO ,或 MATH_ERREXCEPT , 或 MATH_ERRNO | MATH_ERREXCEPT

    std::cout << "MATH_ERRNO is "
              << (math_errhandling & MATH_ERRNO ? "set" : "not set") << '\n'
              << "MATH_ERREXCEPT is "
              << (math_errhandling & MATH_ERREXCEPT ? "set" : "not set") << '\n';
    std::feclearexcept(FE_ALL_EXCEPT);
    errno = 0;
    std::cout <<  "log(0) = " << std::log(0) << '\n';
    if(errno == ERANGE)
            std::cout << "errno = ERANGE (" << std::strerror(errno) << ")\n";
    if(std::fetestexcept(FE_DIVBYZERO))
        std::cout << "FE_DIVBYZERO (pole error) reported\n";

    https://en.cppreference.com/w/cpp/numeric/math/math_errhandling

第15章 并发

  1. scoped_lock 允许同时获取多个锁。

    scoped_lock lck { mutex1, mutex2, mutex3 };
  2. shared_mutex 支持读写锁机制。

    shared_mutex mx;
    
    void reader()
    {
        shared_lock lck { mx };
    }
    
    void writer()
    {
        unique_lock lck { mx };
    }

第16章 历史和兼容性


文章作者: Kiba Amor
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 Kiba Amor !
  目录