條款四 確定對象被使用前已被初始化
一、未初始化的危害
使用未初始化的值會導致不明確的行為
二、內(nèi)置類型的初始化
對于內(nèi)置的數(shù)據(jù)類型(char,int,float,double等),在使用前必須進行初始化。
構(gòu)造函數(shù)
對于class來說,在使用對象之前,必須使用構(gòu)造函數(shù)對成員變量進行初始化
但是需要注意賦值和初始化的區(qū)別
構(gòu)造函數(shù)中的賦值操作(非初始化)
例如下面的構(gòu)造函數(shù)中,對成員變量的都不是初始化,而是賦值操作
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;
}
成員初始化列表(真正的成員變量初始化)
如果想要對成員進行初始化,應該是在構(gòu)造函數(shù)的成員初始化列表對成員數(shù)據(jù)進行初始化
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;
};
為什么成員初始化列表比普通賦值效率高
在構(gòu)造函數(shù)內(nèi)對數(shù)據(jù)成員賦值而言效率更低,因為它們先需要調(diào)用class的默認構(gòu)造函數(shù)對成員數(shù)據(jù)進行默認的初始化,然后再調(diào)用各個成員的拷貝構(gòu)造函數(shù)來進行復制
成員初始化列表:成員初始化列表是在執(zhí)行構(gòu)造函數(shù)體前運行的代碼,因此它們是真正的對數(shù)據(jù)成員進行初始化
成員初始化順序
越在前面的成員變量越先被初始化,與成員變量的定義順序無關(guān)
靜態(tài)對象初始化問題
靜態(tài)對象的聲明周期從定義開始,知道程序結(jié)束為止
*靜態(tài)成員分為哪幾類?
①非局部的靜態(tài)對象:全局靜態(tài)對象、定義與namespace作用域內(nèi)的對象、class的靜態(tài)成員。
②局部的靜態(tài)對象:函數(shù)內(nèi)部的局部靜態(tài)變量
本文主要探討在不同編譯單元之間定義“非局部的靜態(tài)對象”的初始化順序問題
如現(xiàn)在有一個FileSystem類,它類似一個文件系統(tǒng),定義如下
class FileSystem
{
public:
std::size_t numDisks()const;
};
extern FileSystem tfs;
現(xiàn)在客戶端程序在Directiry.h中建立Directory類用來處理文件系統(tǒng)內(nèi)的目錄
#include "FileSystem.h"
class Directory
{
public:
Directory();
}
Directory::Directory()
{
std::size_t disks = tfs.numDisks();
}
// 現(xiàn)在客戶在主程序中創(chuàng)建一個對象來放置臨時文件
Directory tempDir;
這里就會出現(xiàn)問題:如果要使用tempDir,必須保證tfs對象已被初始化,但是tfs對象與tempDir對象是出于不同編譯單元之間的對象,那怎樣才能保證tfs在tempDir使用之前已經(jīng)被初始化了呢?答案是沒有這種方法可以確保。
對于上述問題的解決方法:
將需要用到的非局部靜態(tài)對象封裝到一個函數(shù)內(nèi),對象在函數(shù)內(nèi)部被聲明為static,然后函數(shù)返回一個指向這個對象的引用。用戶之后調(diào)用這些函數(shù),而不是直接調(diào)用這個對象。此處非局部靜態(tài)對象被局部對象替換了。這在設(shè)計模式中,是Singleton模式的一種常見方法。
這種手法保證:函數(shù)內(nèi)的局部靜態(tài)對象會在“該函數(shù)被調(diào)用期間”被初始化
class FileSystem
{
public:
std::size_t numDisks()const;
}
FileSystem& tfs()
{
static FileSystem tfs;
return fs;
}
更改Directory.h文章來源:http://www.zghlxwxcb.cn/news/detail-743763.html
#include "FileSystem.h"
class Directory
{
public:
Directory();
};
Directory::Directory()
{
std::size_t disks = tfs.numDisks();
}
Directory& tempDir()
{
static Directory td;
return td;
}
因此,為了避免跨編譯單元之間初始化次序的問題,請用局部靜態(tài)對象替換非局部靜態(tài)對象文章來源地址http://www.zghlxwxcb.cn/news/detail-743763.html
到了這里,關(guān)于Effective C++ 條款四的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!