1 前言

要想写出好的C++程序,不必了解C++的所有细节。

以C++17标准为最新定义,快速了解现代C++语言:

$ g++ -std=c++17 file.cpp

2 auto与列表初始化

变量优先使用通用的列表初始化形式 {} ,以避免在类型转换中丢失信息:

int i1 = 7.8; // i1变成了7,隐式收缩转换
int i2 {7.8};  // 错误: 浮点数向整数转换
int i2 = {7.8};  // 错误: 浮点数向整数转换

变量类型在没有特殊理由需要显式指定数据类型时,一般使用 auto :

auto b = true;    // bool
auto ch = 'x';    // char
auto i = 123;     // int
auto d = 1.2;     // double
auto z = sqrt(y); // sqrt的返回类型
auto bb {true};   // bool

特殊理由包括:

  • 位于一个较大的作用域中,希望提高代码的易读性,明确数据类型
  • 需要明确一个变量的范围和精度,比如希望使用double而不是float

3 空指针: nullptr

不再使用 0NULL 表示空指针,使用 nullptr ,所有指针类型都共享同一个 nullptr.

检验变量是否为 0nullptr 尽量采用简洁形式:

while(*p) // 等同: while(*p != 0)
{
  //...
}

if(p)  // 等同: if(p != nullptr)
{
  //...
}

void do_something(const vector<int>& v)
{
    if(auto n = v.size())
    {
        // n != 0
    }
}

4 尽量不直接使用union

比如有这样一个联合的定义:

enum Type {ptr, num };

union Value {
    Node *p;
    int i;
};

struct Entry {
    Type t;
    Value v;
};

void f(Entry* pe) {
    if(pe->t == num) {
        cout << pe->v.i;
    }
}

尽量少使用这种原始union形式,改为使用标准库类型variant,并且应该封装到一个类内部从而只为它服务:

#include <variant>

struct Entry {
    Type t;
    std::variant<Node *, int> v;
};

void f(Entry* pe) {
    if(std::holds_alternative<int>(pe->v)){
        std::cout << std::get<int>(pe->v);
    }
}

5 枚举优先使用enum class

以往的enum中枚举值作用域与enum作用域一致,隐式转换为int类型值:

enum Color {red, green, blue};  // 从0开始
enum Clolor2 {red2=1, green2, blue2};  // 从1开始

int col = green; // 1
int col2 = green2; // 2

使用带强类型的枚举则不会出现名字冲突,而且避免了隐式转换:

enum class Color;  // 可以前置声明

enum class Color { red, green, blue};
enum class Color2 { red=1, green, blue};

Color col = Color::green;
Color2 col2 = Color2::green;

int col_i = static_cast<int>(Color::green); // 1, 需要显式转换为int
int col2_i = static_cast<int>(Color2::green); // 2