Effective C++ 条款四

条款四 确定对象被使用前已被初始化

一、未初始化的危害

使用未初始化的值会导致不明确的行为

二、内置类型的初始化

对于内置的数据类型(char,int,float,double等),在使用前必须进行初始化。

构造函数

对于class来说,在使用对象之前,必须使用构造函数对成员变量进行初始化
但是需要注意赋值和初始化的区别

构造函数中的赋值操作(非初始化)
例如下面的构造函数中,对成员变量的都不是初始化,而是赋值操作

class PhontNumber{};
class ABEntry
{
public:
	ABEntry(const std::string& name, const std::strinf& address, const std::list<PhontNumber>& phones);
private:
	std::string theName;
	std::string theAddress;
	std::list<PhontNumber> thePhones;
	int numTimesConsulted;
}
ABEntry::ABEntry(const std::string& name, const std::strinf& address, const std::list<PhontNumber>& phones)
{
	theName = name;
	theAddress = address;
	thePhones = phones;
	numTimeConsulted = 0;
}

成员初始化列表(真正的成员变量初始化)
如果想要对成员进行初始化,应该是在构造函数的成员初始化列表对成员数据进行初始化

class PhontNumber {};
class ABEntry
{
public:
    //成员初始化列表初始化:真正的初始化
    ABEntry(const std::string& name, const std::string& address,
        const std::list<PhontNumber>& phones)
        :theName(name), theAddress(address), thePhones(phones), numTimesConsulted(0)
    {}
private:
    std::string theName;
    std::string theAddress;
    std::list<PhontNumber> thePhones;
    int numTimesConsulted;
};

为什么成员初始化列表比普通赋值效率高

在构造函数内对数据成员赋值而言效率更低,因为它们先需要调用class的默认构造函数对成员数据进行默认的初始化,然后再调用各个成员的拷贝构造函数来进行复制
成员初始化列表:成员初始化列表是在执行构造函数体前运行的代码,因此它们是真正的对数据成员进行初始化

成员初始化顺序

越在前面的成员变量越先被初始化,与成员变量的定义顺序无关

静态对象初始化问题

静态对象的声明周期从定义开始,知道程序结束为止
*静态成员分为哪几类?
①非局部的静态对象:全局静态对象、定义与namespace作用域内的对象、class的静态成员。
②局部的静态对象:函数内部的局部静态变量

本文主要探讨在不同编译单元之间定义“非局部的静态对象”的初始化顺序问题
如现在有一个FileSystem类,它类似一个文件系统,定义如下

class FileSystem
{
public:
	std::size_t numDisks()const;
};

extern FileSystem tfs;

现在客户端程序在Directiry.h中建立Directory类用来处理文件系统内的目录

#include "FileSystem.h"
class Directory
{
public:
	Directory();
}
Directory::Directory()
{
	std::size_t disks = tfs.numDisks();
}

// 现在客户在主程序中创建一个对象来放置临时文件
Directory tempDir;

这里就会出现问题:如果要使用tempDir,必须保证tfs对象已被初始化,但是tfs对象与tempDir对象是出于不同编译单元之间的对象,那怎样才能保证tfs在tempDir使用之前已经被初始化了呢?答案是没有这种方法可以确保。

对于上述问题的解决方法:
将需要用到的非局部静态对象封装到一个函数内,对象在函数内部被声明为static,然后函数返回一个指向这个对象的引用。用户之后调用这些函数,而不是直接调用这个对象。此处非局部静态对象被局部对象替换了。这在设计模式中,是Singleton模式的一种常见方法。
这种手法保证:函数内的局部静态对象会在“该函数被调用期间”被初始化

class FileSystem
{
public:
	std::size_t numDisks()const;
}
FileSystem& tfs()
{
	static FileSystem tfs;
	return fs;
}

更改Directory.h

#include "FileSystem.h"
class Directory
{
public:
	Directory();
};
Directory::Directory()
{
	std::size_t disks = tfs.numDisks();
}

Directory& tempDir()
{
	static Directory td;
	return td;
}

因此,为了避免跨编译单元之间初始化次序的问题,请用局部静态对象替换非局部静态对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值