zoukankan      html  css  js  c++  java
  • 条款04:确定对象被使用前已被初始化

    记住:永远在使用对象前先将它初始化。

    1、不要混淆赋值assignment和初始化initialization。

    ABEntry::ABEntry(const std::string& name,const std::string& address,const std::list<PhoneNumber>& phones)//版本1
    {
         theName = name;//这些都是赋值而非初始化
         theAddress = address;
         thePhones = phones;
         numTimesConsulted = 0;
    
    }
    
    ABEntry::ABEntry(const std::string& name,const std::string& address,const std::list<PhoneNumber>& phones)//版本2
    :theName(name),//调用thename的默认构造函数
       theAddress (address),//下面也是一样操作
       thePhones (phones),
       numTimesConsulted (0)
    { }

    记住如果没有在构造函数的初始化成员列表中显式地初始化成员,则该成员将在构造函数体之前执行默认初始化,比如说上面第一个,在进行赋值之前,theName会调用默认构造函数执行初始化操作。

    初始化和赋值的区别事关底层效率问题,前面直接使用拷贝构造函数进行初始化,后者则先默认初始化然后才调用拷贝赋值运算符进行赋值。

    拷贝构造函数的概念:如果构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则该构造函数就是拷贝构造函数。

    如果成员变量是const或references,它们就一定需要初值,不能被赋值。

    C++有着十分固定的成员初始化顺序。基类早于派生类被初始化,而class的成员变量总是以其声明次序被初始化。

    2、local static对象替换non-local static对象

    函数内的static对象称为local static对象(因为它们对函数而言是local),其他static对象称为non-local static对象。

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

    C++对定义于不同编译单元内的non-local static对象的初始化次序并无明确的定义。

    class FileSystem{
    public:
          ...
         std::size_t numDisks() const;
         ...
    };
    extern FileSystem tfs;//其他文件定义,调用就行
    class Directory{
    public:
         Directory(params);
         ... 
    };
    Directory::Directory(params){
         ...
        std::size_t disks = tfs.numDisks();
        ...
    }

    现在创建一个Directory对象:

    Directory tempDir(params);

    上面的例子初始化顺序就很重要,如果tempDir在使用tfs之前,tfs还没有被初始化,那么就会出问题。

    为了解决这个问题,可以使用单例模式:把非局部静态变量封装到函数中,并返回一个对该变量的引用。

    因为C++保证函数内的local static对象会在该函数被调用期间,首次遇上该对象之定义式时被初始化。

    class FileSystem{...};
    FileSystem& tfs(){//这个函数用来替换tfs对象
         static FileSystem fs;
         return fs;
    
    }
    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对象。
  • 相关阅读:
    MongoDB--CSharp Driver Quickstart .
    关于 IIS7.0下文件写入无权限的解决办法
    Android和WCF通信
    要想有什么样的成就就要有什么样的眼光
    DateTime.Now.ToString() 用法
    机械硬盘怎么看是否4k对齐
    【.Net】在WinForm中选择本地文件
    【.Net】C#获取Windows系统特殊文件夹的路径
    【Python】Python网络编程
    【Asp.Net Core】在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序
  • 原文地址:https://www.cnblogs.com/dingxiaoqiang/p/8018143.html
Copyright © 2011-2022 走看看