2018年10月22日 星期一

[Effective C++] Make sure that objects are initialized before they're used

/* 確保 object 在被使用前已初始化 */

// 1. Reading uninitialized values yields undefined behavior
// 2. Best: always initialize your objects before you use them

// Non-member objects of built-in types
int x = 0;
const char * text = "A C-style string";

double d;
std::cin >> d;

// For almost everything else: make sure that all ctor initialize everything in the object
class PhoneNumber {};
class ABEntry {
public:
 ABEntry();
 ABEntry(const string& name, const string& address, const std::list<PhoneNumber> &phones);

private:
 std::string theName;
 std::string theAddress;
 std::list<PhoneNumber> thePhones;
 int numTimesConsulted;
};
ABEntry::ABEntry(const string& name, const string& address, const std::list<PhoneNumber>& phones)
{
 theName = name;
 theAddress = address;
 thePhones = phones;
 numTimesConsulted = 0;
 // these are all assignments not initializations
}

// 1. The data members of an object are initialized before the body of a constructor is entered.
// 2. Use the member initialization list instead of assignments: more efficient
ABEntry::ABEntry(const string& name, const string& address, const std::list<PhoneNumber>& phones)
 :theName(name), theAddress(address), thePhones(phones), numTimesConsulted(0) // these are now all initializations
{}

// Default-construct a data member
ABEntry::ABEntry()
 : theName(), theAddress(), thePhones(), numTimesConsulted(0)
{}

// For data member that are const or are references must be initialized by initialization list

// 1. Duplication when multiple ctors: by a single private function that all the ctors call.
// 2. In general, true member initialization(via an initialization list) is preferable to pseudo-initialization via assignment

// Initialization order: base class before derived class, data member is initialized in the order where they are declared.

// 1. Static object: one that exists from the time it's constructed until the end of the program, automatically 
// destroyed when the program exits, i.e., dtors automatically called when main finishes executing.
// 2. local static object: static objects inside functions; non-local static object: others
// 3. A translation unit: source code giving rise to a single object file (a single source file + all of its #include files)
// 4. 若一個 translation unit 的 non-local static object 之初始化用到另一個 translation unit 中的 non-local static object, 則
// 被使用的 object 可能未被初始化 -> 因為定義在不同 translation unit 的 non-local static objects 之初始化相對順序是未定義的
class FileSystem {
public:
 std::size_t numDisks() const;
};
extern FileSystem tfs;

class Directory {
public:
 Directory(void * pParams);
};
Directory::Directory(void * pParams)
{
 std::size_t disks = tfs.numDisks();
}
Directory tempDir(nullptr);// static object: global variable
// How can we be sure tfs will be initialized before tempDir? No Way.

// Solution: Singleton Pattern
FileSystem& tfs() // could be a static member function in the FileSystem class
{
 static FileSystem fs;
 return fs;
}
Directory::Directory(void * pParams)
{
 std::size_t disks = tfs().numDisks();
}
Directory& tempDir() // could be a static member function in the Directory class
{
 static Directory td;
 return td;
}
// 1. If never call, never incur the cost of constructing and destructing the object
// 2. Excellent candidates for inlining

// 1. Function contain static objects makes them problematic in multi-threaded systems.
// 2. Solution: manually invoke all the reference-returning functions during the single-threaded startup portion of the program.

沒有留言:

張貼留言