首页 > 其他分享 >Item 4:确保对象在使用前被初始化

Item 4:确保对象在使用前被初始化

时间:2024-03-30 14:12:10浏览次数:34  
标签:std 初始化 const string ABEntry Item 确保 构造函数

芝士wa
2024.3.30
Item4链接


“ 在C++中,读取一个未初始化的值会引起未定义行为,在一些平台上,读一个未初始化值会引起程序终止,更可能的情况是得到一个你所读的那个位置上的semi-random bits(半随机二进制位),最终导致不可预测的程序行为和恼人的调试。”

初始化列表

通过构造函数进行初始化
坏的例子:

class ABEntry {   // ABEntry = "Address Book Entry"

public:

  ABEntry(const std::string& name, const std::string& address,
          const std::list<PhoneNumber>& phones);

private:

  std::string theName;

  std::string theAddress;

  std::list<PhoneNumber> thePhones;

  int num TimesConsulted;

};

ABEntry::ABEntry(const std::string& name, const std::string& address,
                 const std::list<PhoneNumber>& phones)

{

  theName = name;                       // these are all assignments,

  theAddress = address;                 // not initializations

  thePhones = phones;

  numTimesConsulted = 0;

}

这种初始化的方法是通过在函数体内复制,但还不是最好的做法。C++ 的规则规定一个 对象的数据成员在进入构造函数的函数体之前被初始化。在 ABEntry 的构造函数内,theName,theAddress 和 thePhones 不是被初始化,而是被赋值。

初始化发生得更早——在进入 ABEntry的构造函数的函数体之前,它们的 default constructors(缺省的构造函数)已经被自动调用。但不包括 numTimesConsulted,因为它是一个 built-in type(内建类型)。不能保证它在被赋值之前被初始化。

一个更好的方法是用 member initialization list(成员初始化列表)来代替 assignments(赋值),写法如下:

ABEntry::ABEntry(const std::string& name, const std::string& address,
                 const std::list<PhoneNumber>& phones)

: theName(name),
  theAddress(address),                  // these are now all initializations
  thePhones(phones),
  numTimesConsulted(0)

{}                                      // the ctor body is now empty

这种写法通常具有更高的效率,因为基于赋值的版本会首先调用缺省构造函数初始化theName,theAddress和thePhones,然而又进行了赋值操作,那些缺省构造函数所做的工作被浪费了。初始化列表的方法避免了这个问题,只需要调用依次拷贝构造函数。


初始化顺序

对于多文件编程的场景,如果一个文件用到了另一个文件中的全局变量,无法确定初始化顺序,可能会导致错误。
解决办法:

  • 将全局静态对象移到自己的函数内部
  • 在函数内部将其声明为局部静态对象
  • 函数返回对局部静态对象的引用

工作原理:
C++ 保证局部静态对象的初始化发生在因为调用那个函数而第一次遇到那个对象的定义时。

class FileSystem {                    // from your library

public:
  ...
  std::size_t numDisks() const;       // one of many member functions
  ...
};

extern FileSystem tfs;                // object for clients to use;
                                      // "tfs" = "the file system"
FileSystem& tfs()                   // this replaces the tfs object; it could be
{                                   // static in the FileSystem class
  static FileSystem fs;             // define and initialize a local static object
  return fs;                        // return a reference to it
}

class Directory { ... };            // as before

Directory::Directory( params )      // as before, except references to tfs are
{                                   // now to tfs()
  ...
  std::size_t disks = tfs().numDisks();
  ...
}

Directory& tempDir()                // this replaces the tempDir object; it
{                                   // could be static in the Directory class
  static Directory td;              // define/initialize local static object
  return td;                        // return reference to it
}

总结

手动初始化 built-in type(内建类型)的 objects(对象),因为 C++ 只在某些时候才会自己初始化它们。

在 constructor(构造函数)中,用 member initialization list(成员初始化列表)代替函数体中的 assignment(赋值)。initialization list(初始化列表)中 data members(数据成员)的排列顺序要与它们在 class(类)中被声明的顺序相同。

通过用 local static objects(局部静态对象)代替 non-local static objects(非局部静态对象)来避免跨 translation units(转换单元)的 initialization order problems(初始化顺序问题)。

标签:std,初始化,const,string,ABEntry,Item,确保,构造函数
From: https://www.cnblogs.com/cheese-wa/p/18105408

相关文章

  • MogDB 2.1.1 初始化参数概要说明
    MogDB2.1.1初始化参数概要说明本文出处:https://www.modb.pro/db/394787MogDB数据库安装完成后,官方文档提供了刷新参数的脚本,推荐执行脚本来进行初始化参数设置。本文在官方提供脚本的基础上添加了简单说明,方便新学习的同学能大概了解参数作用。CentOS7.7下标准安装MogDB......
  • 鸿蒙HarmonyOS实战-ArkUI组件(Grid/GridItem)
    ......
  • Item2:用consts,enums和inlines取代#defines
    芝士wa2024.3.29Item2链接“用compiler(编译器)取代preprocessor(预处理器)”,问题就在于因为#define不被视为语言的一部分要理解这句话,需要先了解C++程序的编译过程:1.预处理preprocess预处理是编译前的准备工作。在这一步中,预处理器会执行以下操作:替换所有的宏定义(#defin......
  • teamcenter 创建Item是带必填项实现
     其中itemUom为度量单位/** * 度量单位的获取 *@Title:getMeasureMap *@Description:TODO *@paramsession *@Author:wushigao *@CreateDate:2022Feb2508:29:00 */ publicstaticMap<String,TCComponentUnitOfMeasure>getMeasureMap(TCSessionsession......
  • 2-18. 创建 InventoryManager 和 Item
    创建Singleton创建InventoryManager创建ItemBase接下来修改碰撞体大小这样写是因为图片的锚点可能在底部,所以需要修改coll.offset项目相关代码代码仓库:https://gitee.com/nbda1121440/DreamOfTheKingdom.git标签:20240328_2045......
  • Qt显示图像之QGraphicsPixmapItem
    为防止不断地addItem导致内存增长,建议在初始化时newItem、scene->addItem。在合适的地方scene->removeItem(或scene->clear)或者item->setVisible。h头文件中#include<QGraphicsView>QGraphicsView*view;QGraphicsScene*scene;QGraphicsPixmapItem*m_pix=nullptr;cp......
  • content可以拿出来下面的子item里设置吗?
    content可以拿出来下面的子item里设置吗?<Buttonx:Name="_button"Content="退出"Width="100"Height="25"Click="_button_Click"IsDefault="True"/>......
  • 【wpf】ListBoxItemIndexConverter转换器listbox序号自更新
    publicclassListBoxItemIndexConverter:IMultiValueConverter{publicobjectConvert(object[]values,TypetargetType,objectparameter,CultureInfoculture){stringindexPrefix=null;if(parameter!=null&&parameter......
  • IRIS / Chronicles 定义 Item 中的 Add Type 属性
    根据我们前面说的Item中的AddType属性,这个主要用来标识输入的数据是不是随着时间的变化而变化,有下面3种选项。No‐Add这个就是当数据输入后,是不会再变化了,不会随着时间的变化而变化。ResponseEachTime这个就是每次在数据在创建的时候都有可能会变化。比如说体重,当你......
  • WPF解决当ScrollViewer中嵌套ItemsControl时,不能使用鼠标来滚动翻页
    1.在DataGrid中添加PreviewMouseWheel事件,并将事件的Handled属性设置为false,以便将滚动事件传递给ScrollViewer。示例代码如下:<DataGridPreviewMouseWheel="DataGrid_PreviewMouseWheel"><!--DataGrid的其他设置--></DataGrid>privatevoidDataGrid_PreviewMouseWh......