zoukankan      html  css  js  c++  java
  • 【Effective C++ 读书笔记】条款04:确定对象使用前已先被初始化

    永远在使用对象之前先将它初始化。对于无任何成员的内置类型,你必须手工完成此事。

    至于内置类型以外的任何其他东西,初始化责任落在构造函数身上。规则很简单:确保每一个构造函数都将对象的每一个成员初始化。

    构造函数成员初始化列表:
    这里有一个规则:总是在初始化列表中列出所有成员变量,即使有的成员变量是内置类型(内置类型的初始化和赋值成本相同)。

    成员初始化顺序
    base classes 早于 derived classes 被初始化,class 的成员变量总是以其声明次序被初始化


    一个编译单元内定义的”non-local static对象“的初始化次序

    static 对象,其寿命从被构造出来知道程序结束为止。
    static 对象包括 global 对象、定义于 namespace 作用域内的对象、在class内、在函数内、以及在file 作用域内被声明为 static 的对象。
    函数内的 static 对象称为 local static 对象,其他的称为 non-local static 对象。
    程序结束时 static对象会被自动销毁。

    编译单元是指产出单一目标文件的那些源码。基本上是单一源文件加上其所含入的头文件。

    如果某个编译单元内的 non-local static 对象的初始化动作使用了另一个编译单元内的某个 non-local static 对象,他所用到的这个对象可能尚未被初始化。

    举个实例加以理解:

    //file1: Filesystem.cpp
    //
    class FileSystem{
        public:
        std:size_t numDisks() const
    };
    
    extern FileSystem tfs;
    
    
    //file2:Directory.cpp
    //
    class Directory{
        public:
            Directory(params);
    };
    
    Directory::Directory(params)
    {
        std::size_t disks = tfs.numDisks();   //使用 tfs 对象
    }
    
    int main()
    {
        Directory tempDir( params );
    }
    
    //这个时候初始化的重要性显现出来了,tfs必须在tempdir之前被初始化,否则tempDir的构造函数就会用到尚未初始化的tfs。
    //但是C++对于不同编译单元内的 non-local static对象的初始化相对次序并无明确定义。
    //为了消除这个问题:
    //采用 设计模式中的 Singleton 模式的一个常见实现手法:将每个 non-local static 对象搬到自己的专属函数内(该对象在此函数内被声明为static)
    //
    //这个手法的基础就是:C++ 保证,函数内的 local static对象会在“该函数被调用期间”“首次遇上该对象之定义式”时被初始化,这样就保证你所获得的reference将指向一个历经初始化的对象
    //
    //将此技术实施于 tfs 和 tempDir 身上:
    //file1: Filesystem.cpp
    //
    class Filesystem { ... }; //同前
    FileSystem& tfs()
    {
        static FileSystem fs;
        return fs;
    }
    
    //file2:Directory.cpp
    class Directory{ ... };
    Directory::Directory( params )
    {
        std::size_t disks = tfs().numDisks();
    }
    
    Directory& tempDir()
    {
        static Directory td;
        return td;
    }

    【请记住:】

    • 为内置类型对象进行手工初始化,因为 C++ 不保证初始化它们。
    • 构造函数最好使用成员初始化列表,而不要在构造函数本体内使用赋值操作。
    • 构造函数初始化列表中的成员变量排列次序应该和他们在 class 中的声明次序相同。
    • 为免除 ”跨编译单元值初始化次序“问题,请以 local static 对象替换 non-local static 对象。

  • 相关阅读:
    洛谷P1023 税收与补贴问题
    洛谷P2680 运输计划
    2014-11-3 NOIP模拟赛3
    一行Python代码就可以玩一些童年小游戏
    NuGet(微软.NET开发平台的软件包管理工具)在VisualStudio中的安装的使用
    Winform中实现序列化指定类型的对象到指定的Xml文件和从指定的Xml文件中反序列化指定类型的对象
    Electron中打开和关闭子窗口以及子窗口向父窗口传值
    Electron中实现通过webview实现内嵌网页并嵌入css样式和js脚本等
    Electron中实现拖拽文件进div中通过File对象获取文件的路径和内容
    Electron中通过process进程对象的api获取CPU、系统位数、环境变量等相关信息
  • 原文地址:https://www.cnblogs.com/lanqiu5ge/p/9472208.html
Copyright © 2011-2022 走看看