跳转至

Modern C++

本文开篇将快速过一遍C++的基础语法,从类与对象开始逐渐深入,最后涉及现代C++(C++17之后)的语法特性。

当然,C++的书大几百万字,您也无法在本教程中完全掌握C++,因而本教程只能尽可能的带您遍览一遍C++的语法特性。

C++ 基础

  • 数据类型 bool char int float double void(无类型)
  • 修饰符 signed unsigned short(2 byte) long(8 byte) const。volatile(表示变量可能被意外修改,禁止编译器优化,确保每次从内存中去读取) mutable(表示类成员可以在 const 对象中修改,但有些变量只是辅助用途,并不是对象核心状态,所以可以修改。)

数组、指针、引用、函数、结构体、类等请详见 C++ 类 & 对象 | 菜鸟教程

函数

函数中值得一提的是lambda 表达式: Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

1
[capture](parameters)->return-type{body}
  • [capture] 是捕获列表,指定了lambda的传入值的方式,有引用传值,常见的有[&][=] ,分别代表这按值捕获和按引用捕获外部变量。

  • [parameter] 是参数列表,用于表示 Lambda表达式的参数,可以为空,表示没有参数,也可以和普通函数一样指定参数的类型和名称,还可以在 c++14 中使用 auto 关键字来实现泛型参数。

  • [return type] 是返回值类型,用于指定 Lambda表达式的返回值类型,可以省略,表示由编译器根据函数体推导,也可以使用 -> 符号显式指定,还可以在 c++14 中使用 auto 关键字来实现泛型返回值。
  • [body] 是函数体,用于表示 Lambda表达式的具体逻辑,可以是一条语句,也可以是多条语句,还可以在 c++14 中使用 constexpr 来实现编译期计算。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
auto lambdaTest() -> void {
  int x = 10;
  auto lambda = [&](int a) -> int { int z = x + a; x++ ;return z + x;};
  std::cout << lambda(1) << std::endl;
  std::cout << "lambda Test End" << std::endl; // 输出22
}

auto modern_main() -> void {
  lambdaTest();
}

想要学习lambda,上述内容仍远不及,参考:

移动语义

一个应用场景是锁,当对象A和B都有机会获得对于C的写入/读取锁时,A获得锁后,B若已经有锁,则A需要从B中拿锁,B的锁将销毁。

RAII

RAII 全称是 Resource Acquisition Is Initialization,中文常译为资源获取即初始化。核心思想很简单也很强大:把资源的生命周期绑定到对象的生命周期——在对象构造时获取资源(如内存、文件句柄、锁、网络连接等),在对象析构时释放资源。这样可以保证不论函数如何返回(正常返回或抛出异常),资源都能被正确释放,实现异常安全与简洁的资源管理。

智能指针

主要是三个:std::weak_ptr<T>,std::shared_ptr<T>,std::unique_ptr<T>

noexcept

noexcept是C++11引入的关键字,用于指定函数是否会抛出异常。它有两种用途:作为说明符(声明函数不会抛出异常)和作为运算符(检查表达式是否会抛出异常)。

Arg模板参数包

一个例子是SocketCAN与电控下层板通信时,需要将多个参数写入一个CAN报文。CAN报文的大小这里是64字节,如果使用double类型(8 bytes)的变量,可以一条报文放下8个double。使用模板参数包的好处是可以多个double,甚至是double、float、int混用共同塞入一条CAN报文,只要大小不超过64字节。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void fill_with(void *_dst, Args &&... _args)
{
    static_assert(((sizeof(Args) + ...) < 64), "args too large");
    (void)std::initializer_list<int>{
        ([&]{
            memcpy(_dst, std::addressof(_args), sizeof(_args));
        }(), 0
        )...
    };
}