C++核心指南——C++创始人参与编写的代码指南笔记及翻译


  • P:Philosophy
    • P.1 Express ideas directly in code 直接用代码表达思想

      不直接使用语言的原始数据类型名,变量的类型名应该与变量的含义相关

      Month month() const;  // Good!
      int month();          // Bad!

      优先使用设计良好库来代替原始的语句,表达更加清楚的意图

      • for循环的意图是查找一个元素
      //BAD
      void f(vector<string>& v)
      {
          string val;
          cin >> val;
          // ...
          int index = -1;                    // bad, plus should use gsl::index
          for (int i = 0; i < v.size(); ++i) {
              if (v[i] == val) {
                  index = i;
                  break;
              }
          }
          // ...
      }
      • 更好的表达:使用一个find函数来表达查找的意图
      //GOOD
      void f(vector<string>& v)
      {
          string val;
          cin >> val;
          // ...
          auto p = find(begin(v), end(v), val);  // better
          // ...
      }
    • P.2 Write in ISO Standard C++ 使用C++标准编写代码

    • P.3 Express intent 表达意图

      除了在变量类型中表达意图外,在代码中也要体现精确的意图

      • 遍历容器中的元素的操作

        • BAD:使用意义不明的while循环和超出循环生命期的i变量

          gsl::index i = 0;
          while (i < v.size()) {
              // ... do something with v[i] ...
          }
        • BATTER:使用范围for,明确表达遍历意图

          // 不修改元素版本
          for (const auto& x : v) { /* do something with the value of x */ }
          // 修改元素版本
          for (auto& x : v) { /* modify x */ }
        • BATTER:使用一个命名算法,能够更加明确表达遍历的意图,且还包含对容器中元素顺序不感兴趣

          for_each(v, [](int x) { /* do something with the value of x */ });
          for_each(par, v, [](int x) { /* do something with the value of x */ });
      • Note

        • Alternative formulation: Say what should be done, rather than just how it should be done.
        • 替换表达:说做什么而不是怎么做。
        • Some language constructs express intent better than others.
        • 有些语言结构比其他语言结构更好地表达意图。
    • P.4 Ideally, a program should be statically type safe 理想情况下程序应该是静态类型安全的

      • 类型安全:对于程序的类型安全来说,不会出现类型错误就是类型安全
      • 静态类型安全:代码编写过程中保证类型是安全,在编写代码时及时检查类型
      • 理想情况下,程序应该保证完全类型安全,包括静态和编译期类型安全,但是这几乎做不到,所以退而求其次,保证静态类型安全
      • 容易出现类型不安全的情况
        • unions 联合体
        • casts 类型转换
        • array decay 数组退化
        • range errors 范围错误
        • norrowing conversions 窄化类型转换
      • 类型不安全解决办法
        • union:使用 variant(C++17) 代替
        • casts:尽量不使用类型转换,适当用模板功能替换
        • array decay:使用span来访问数组
        • range errors:使用span来访问数组
        • norrowing conversions:尽量不使用窄化类型转换,必要时候用narrow_cast替代
    • P.5 Prefer compile-time checking to run-time checking 选择编译时检查而不是运行时检查

      • 不要把在编译期能够完成的事情留到运行期做‘

      • 类型检查

        • BAD:在运行期进行类型检查

          // Int是整数类型的一个别名
          // 代码段的功能是确保Int类型的大小大于4字节
          int bits = 0;         // 这种写法,不可避免的额外变量
          for (Int i = 1; i; i <<= 1)
              ++bits;
          if (bits < 32)
              cerr << "Int too small\\n";
        • BATTER:使用编译期断言来进行类型检查

          // Int是int类型的一个别名
          static_assert(sizeof(Int) >= 4);    // 编译期检查
      • 数组大小检查

        • BAD:运行时指定数组大小,又可能会超范围

          void read(int* p, int n);   // 从p中读取最多的n个数
          
          int a[100];
          read(a, 1000);    // 提供的n大于数组范围,导致数组越界
        • BATTER:编译器计算数组大小

          void read(span<int> r); // 读入整数r的范围
          
          int a[100];
          read(a);        // 让编译器去计算数组长度
    • P.6 What cannot be checked at compile-time should be checked at run-time 无法在编译期检查的问题需要在运行期检查

      • 对于程序中可能出现的错误都需要进行检查,难以检测的错误会导致程序的崩溃和出现错误结果
      • 理想情况下,应该捕获所有错误,但是实际根做不到。不过函数应该尽可能捕获能捕获的错误
    • P.7 Catch run-time errors early 尽量早地捕获运行期错误

      • 在数组越界访问前检查访问范围

        • BAD:m可能越界,但是直到访问到p[10]时才会被发现

          void increment1(int* p, int n)    // bad: error-prone
          {
              for (int i = 0; i < n; ++i) ++p[i];
          }
          
          void use1(int m)
          {
              const int n = 10;
              int a[n] = {};
              // ...
              increment1(a, m);   // maybe typo, maybe m <= n is supposed
                                  // but assume that m == 20
              // ...
          }
        • BATTER:在访问前会检查范围,在访问数组元素前就会出错

          void increment2(span<int> p)
          {
              for (int& x : p) ++x;
          }
          void use2(int m)
          {
              const int n = 10;
              int a[n] = {};
              // ...
              increment2({a, m});    // maybe typo, maybe m <= n is supposed
              // ...
          }
      • Enforcement

        • Look at pointers and arrays: Do range-checking early and not repeatedly
        • 对于指针和数组:尽早进行范围检查且避免见检查重复
        • Look at conversions: Eliminate or mark narrowing conversions
        • 对于转换:剔除或者明确标记窄化转换
        • Look for unchecked values coming from input
        • 注意从输入带来的未检查值
        • Look for structured data (objects of classes with invariants) being converted into strings
        • 注意被转换为strings的结构化数据
    • P.8 Don’t leak any resources 不要泄漏任何资源

      • leak:anything that isn't cleaned up

      • 打开文件

        • BAD:直接使用文件结构体

          void f(char* name)
          {
              FILE* input = fopen(name, "r");
              // ...
              if (something) return;   // bad: if something == true, a file handle is leaked
              // ...
              fclose(input);
          }
        • BETTER:使用文件流对象,RAII

          void f(char* name)
          {
              ifstream input {name};
              // ...
              if (something) return;   // OK: no leak
              // ...
          }
      • 使用RAII机制,利用局部变量的隐式析构作为资源管理方法

      • Enforcement

        • 使用智能指针管理资源
        • 不直接使用new 和delete
        • 注意直接返回原始指针的函数,如fopen、malloc
    • P.9 Don’t waste time or space 不要浪费时间和空间

      • 在C++中投入时间优化时间和空间是值得的
    • P.10 Prefer immutable data to mutable data 选择不可变数据而不是可变数据

      常数要比变量更容易优化,且不存在对于常数的竞争(多线程)

    • P.11 Encapsulate messy constructs, rather than spreading through the code 封装杂乱的构造,而不是在代码中扩展

      • 在能够使用库的地方尽可能使用库

      • BAD

        int sz = 100;
        int* p = (int*) malloc(sizeof(int) * sz);
        int count = 0;
        // ...
        for (;;) {
            // ... read an int into x, exit loop if end of file is reached ...
            // ... check that x is valid ...
            if (count == sz)
                p = (int*) realloc(p, sizeof(int) * sz * 2);
            p[count++] = x;
            // ...
        }
      • BETTER:

        vector<int> v;
        v.reserve(100);
        // ...
        for (int x; cin >> x; ) {
            // ... check that x is valid ...
            v.push_back(x);
        }
    • P.12 Use supporting tools as appropriate 适当地使用支持工具

      • Static analysis tools 静态分析工具
      • concurrency tools 并发工具
      • testing tool 测试工具
    • P.13 Use support libraries as appropriate 适当地使用支持库

#2023一起秋招吧##C/C++#
全部评论
笔记写的非常详细,懂了
点赞 回复 分享
发布于 2022-08-26 19:17 陕西

相关推荐

05-26 10:24
门头沟学院 Java
qq乃乃好喝到咩噗茶:其实是对的,线上面试容易被人当野怪刷了
找工作时遇到的神仙HR
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务