当前位置: 首页 > article >正文

Effective C++ 条款 04:确定对象被使用前已先被初始化

条款 04:确定对象被使用前已先被初始化

目的

确保每个构造函数都能将对象的所有成员初始化,并且使用 成员初值列(Member Initialization List)来完成初始化,而不是在构造函数本体中进行赋值。成员初值列是在构造函数开始时执行的,它确保了成员变量在构造函数体内部使用之前已经被初始化。

关键点

  • 成员初值列:成员初值列是在构造函数的声明部分使用冒号(:)初始化类成员的语法。在构造函数的主体执行之前,成员变量会根据初值列进行初始化。初值列的使用比构造函数体内的赋值语句更加高效。
  • 避免赋值:在构造函数体内使用赋值语句给成员变量赋值不是推荐的做法。应该优先使用成员初值列初始化成员变量。

示例

class ABEntry {
public:
  ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones)
    : theName(name),              // 初始化 theName
      theAddress(address),        // 初始化 theAddress
      thePhones(phones),          // 初始化 thePhones
      numTimesConsulted(0)        // 初始化 numTimesConsulted
  {
    // 这里不再进行成员变量的赋值,避免重复操作
  }
  
private:
  std::string theName;
  std::string theAddress;
  std::list<PhoneNumber> thePhones;
  int numTimesConsulted;
};

上面代码中,theNametheAddressthePhonesnumTimesConsulted 都在成员初值列中初始化,而构造函数体内没有再进行赋值操作,这样能确保每个成员都在对象创建时得到正确的初始化。

手工初始化内置类型对象

C++ 不保证内置类型(如 intdouble 等)会自动初始化,所以建议手动初始化这些成员变量。确保内置类型在使用之前已经赋予一个合理的值。

成员初值列的顺序

在成员初值列中,成员变量应该按照它们在类中声明的顺序来初始化。这是因为 C++ 对象的成员变量初始化顺序是根据它们在类中声明的顺序,而不是在成员初值列中的顺序。

class MyClass {
public:
  MyClass(int a, int b) : x(a), y(b) {} // 按照声明顺序初始化 x 和 y
private:
  int x;
  int y;
};

这段代码确保了 xy 的初始化顺序与它们在类中声明的顺序一致,避免了潜在的问题。

跨编译单元的初始化次序问题

为了避免跨编译单元之间的初始化顺序问题,建议使用 局部静态对象(local static object)来代替 非局部静态对象(non-local static object)。局部静态对象会在第一次调用时进行初始化,因此它们能够在多线程环境下保证线程安全。

示例

class FileSystem { 
  // FileSystem 类的定义 
};

FileSystem& tfs() { 
  static FileSystem fs;  // 局部静态对象,在首次调用时初始化
  return fs; 
}

class Directory { 
public: 
  Directory(/* params */) { 
    std::size_t disks = tfs().numDisks();  // 使用局部静态对象 tfs()
  } 
};

在这段代码中,FileSystem 类的局部静态对象 fs 会在首次调用 tfs() 时被初始化,确保初始化顺序的正确性。

总结

  • 使用 成员初值列 初始化对象的成员变量,避免在构造函数体内进行赋值。
  • 确保内置类型的成员变量手动初始化,避免未定义行为。
  • 初始化顺序应与成员变量在类中的声明顺序一致。
  • 使用 局部静态对象 替代 非局部静态对象,避免跨编译单元的初始化顺序问题。

http://www.kler.cn/a/453802.html

相关文章:

  • NIO(New IO)和BIO(Blocking IO)的区别
  • IBatis和MyBatis在细节上的不同有哪些
  • C++模板:编译时模拟Duck Typing
  • 强化特种作业管理,筑牢安全生产防线
  • 《计算机网络(第7版)-谢希仁》期末考试复习题和答案(总结整理)
  • Anton和Danik的棋局对决
  • flask后端开发(9):ORM模型外键+迁移ORM模型
  • Java重要面试名词整理(七):分库分表
  • redis使用注意哪些事项
  • 深入理解Nginx工作原理及优化技巧
  • 子网掩码计算route命令
  • Spark常用的转化操作和动作操作详解
  • Linux系统编程——理解系统内核中的信号捕获
  • 深度学习-76-大模型量化之压缩映射方法和量化校准方法简介
  • mybatis SqlSessionFactory
  • Java配置文件的使用-相同信息在不同环境的赋值访问
  • 解决在windows中mysql安装服务后启动服务失败的问题
  • 求两大数和
  • 软件开发中 IT 人力外包驻场有哪些优点
  • 《Opencv》基础操作详解(2)
  • 【电商搜索】文档的信息论生成聚类
  • CSS系列(33)-- Perspective详解
  • 搜索模拟版!!!(自创)
  • C/C++ 数据结构与算法【树和二叉树】 树和二叉树,二叉树先中后序遍历详细解析【日常学习,考研必备】带图+详细代码
  • 电压控制环与电流控制环
  • 数学建模与数学建模竞赛