2

Effective Modern C++(4): Modern C++(2)

 1 year ago
source link: https://keys961.github.io/2022/06/05/Effective-Modern-C++(4)/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1. 若不抛异常则使用noexcept

  1. 更好展示函数不会抛出异常

  2. 由于展开异常调用栈对代码生成有影响,因此若不抛出异常,标注noexecpt后,编译器能尽可能优化

  3. 某些操作中有用

    • move操作:例如std::vector::push_back,若对象move函数为noexcept,那么通过调用std::move_if_noexcept,将拷贝操作优化为move操作

  4. 可定义函数视情况noexcept

    • 例如std::swap中数组和std::pair的版本
  5. 大多数函数是异常中立(可能抛也可能不抛),而非noexcept

虽然noexcept可以带来优化,但正确性更重要,若有可能出现异常,则不能加noexcept

2. 尽量使用constexpr

语法:constexpr <expression>

意义:表明expression的值是一定是编译期可知(且一定不变)的。

  • 该值可以放到需要编译期常量的地方(例如模板参数)

  • const不如constexpr,只能保证值不变(例如临时const变量)

constexpr函数:

  • 若传参编译期可知,则结果在编译期可知(即编译时就被计算),可用于放到需要编译期常量的地方

  • 若传参编译期不可知,则等同普通函数,若放到需要编译期常量的地方,则编译错误

  • 函数可以是构造函数、getter和setter,若传参编译期可知,那么结果(包括类中的成员)也编译期可知

  • constexpr是对象和函数接口的一部分

    • 相当于宣称“我能被用在要求常量表达式的地方”

3. 让const成员函数线程安全

因为const函数的意义在于调用时,不会变更成员内部值,返回时一个相同的值。

但是有时候确实必要修改很小一部分内部值,此时可以用mutable修饰这一部分值。

但修改后,多线程下,若不保证线程安全,则行为未定义,从而打破const成员函数的语义。

因此,尽量让const函数线程安全,除非不会并发访问。

4. 特殊成员函数的生成

特殊成员函数:

  • 默认构造函数

  • 拷贝构造函数:T(const T&)

  • 拷贝赋值运算:T& T::operator=(const T&)

  • 移动构造函数:T(T&&)

  • 移动赋值运算:T& T::operator=(T&&)

新增的移动成员函数,默认特点:

  • 对非静态成员逐个move

  • 同样影响父类部分

  • 若成员不支持移动,则会拷贝

总结特殊成员函数的生成和处理规则:

  1. 默认构造函数:仅类没有声明构造函数时生成

  2. 析构函数:仅类没有声明构造函数时生成,且为noexcept

  3. 拷贝构造函数:

    • 没有定义拷贝构造时生成

      • 若声明了移动操作,它默认是delete
    • 逐个拷贝非静态成员

  4. 拷贝赋值运算:

    • 没有定义拷贝赋值时生成

      • 若声明了移动操作,它默认是delete
    • 逐个拷贝非静态成员

  5. 移动操作(构造+赋值运算):

    • 当没定义拷贝、移动和析构操作时生成

    • 逐个移动(调用std::move)非静态成员,若不支持移动,则回退为拷贝

  6. 成员函数的模板不影响生成特殊成员函数的规则


Related Issues not found

Please contact @keys961 to initialize the comment


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK