Objective C ++ Reading Notes (3)

Source: Internet
Author: User

Clause 04: Object initialized before being used

Make sure that objects are initializedbefore they're used.

C ++ seems capricious about initializing objects. In some contexts, the built-in types and class member variables are always initialized, but not in other contexts.

Reading uninitialized values may lead to unclear behavior. It may cause your program to stop running, may pollute the object that is reading, may lead to unknown program behavior, and many unpleasant Debugging Processes.

The best solution is to always initialize the object before using it. You must do this manually for built-in types, pointers, and read input streams.

L manual Initialization is performed for internal objects because C ++ does not guarantee initialization of them.

 

For anything other than the built-in type, Initialization is done by the constructor, ensuring that each constructor initializes every member of the object.

This rule is easy to follow. It is important not to confuse assignment and initialization. Consider a class used to represent the address book. Its constructor is as follows:

1. class PhoneNumber {...};

2. class ABEntry {// ABEntry = "Address Book Entry"

3. public:

4. ABEntry (const std: string & name, const std: string & address,

5. const std: list <PhoneNumber> & phones );

6. private:

7. std: string theName;

8. std: string theAddress;

9. std: list <PhoneNumber> thePhones;

10. int numTimesConsulted;

11 .};

12. ABEntry: ABEntry (const std: string & name, const std: string & address,

13. const std: list <PhoneNumber> & phones)

14 .{

15. theName = name; // These are values (assignments ),

16. theAddress = address; // instead of initialization ).

17. thePhones = phones;

18. numTimesConsulted = 0;

19 .}

This will cause the ABEntry object to carry the value you expect (you specify), but it is not the best practice. C ++ specifies that the initialization action of the object's member variables takes place before entering the constructor ontology. In the ABEntry constructor, theName, theAddress, and thePhones are not initialized, but assigned values. Initialization takes place earlier than when the default constructor of these members is automatically called (earlier than the time it takes to enter the ABEntry constructor ontology ).

It is better to replace the value assignment with the so-called member initialization list (member Initial Value column:

1. ABEntry: ABEntry (const std: string & name, const std: string & address,

2. const std: list <PhoneNumber> & phones)

3.: theName (name ),

4. theAddress (address), // now, these are initialization (initializations)

5. thePhones (phones ),

6. numTimesConsulted (0)

7. {} // currently, the constructor does not have to take any action.

This constructor has the same final result as the previous one, but is usually more efficient. For most types, compared to calling the default constructor and then calling the copy assignment operator, it is more efficient and sometimes even more efficient to call the copy constructor only once. For an internal object such as numTimesConsulted, the initialization and assignment costs are the same, but it is best to initialize it through the member Initial Value column for consistency. Similarly, you can use the initial value column of a member even if you want to construct a member variable by default. Suppose ABEntry has a non-parameter constructor. we can implement it as follows:

1. ABEntry: ABEntry ()

2.: theName (), // call the default constructor of theName;

3. theAddress (), // perform similar actions for theAddress;

4. thePhones (), // perform similar actions for thePhones;

5. numTimesConsulted (0) // remember to explicitly initialize numTimesConsulted to 0

6 .{}

Set a rule to always list all member variables in the initial value column and always use the initial value column.

C ++ has a very fixed "initialization order of members". base classes is earlier than its derived classes, while class member variables are always initialized in the declared order. Looking back at ABEntry, The theName member is always initialized first, then theAddress, thePhones, and numTimesConsulted, even if they appear in different order in the member's initial value column. To avoid some possible obscure errors (the initialization of two member variables is ordered. For example, you must specify the size when initializing the array. Therefore, the member variable representing the size must have an initial value first ), when you column each member in the initial value column of a member, it is best to always order the members in their Declaration Order.

L it is best to use the member Initial Value column (memberinitialization list) in the constructor, instead of using the value assignment operation (assignment) in the constructor itself ). The member variables listed in the initial value column should be arranged in the same order as their declaration in class.

 

Initialization sequence of non-local static objects defined in different compilation units

Static object: The static object in the function is called localstatic object, and other static objects are called non-localstatic objects. Static objects are automatically destroyed when the program ends, that is, their destructor are automatically called at the end of main.

Translation unit: generate the source code of a single object file. Basically, it is a single source file and the header file contained in it (# include files ).

The real problem is: if the initialization action of a non-localstatic object in a compilation unit uses a non-local static object in another compilation unit, the object it uses may not have been initialized, because C ++ does not explicitly define the initialization sequence of "non-local static objects defined in different compilation units.

Suppose you have a FileSystem class, which makes the files on the Internet look like they are located locally ). Because this class makes the world look like a single file system, you may produce a special object in the global or namespace scope, symbolizing a single file system:

1. class FileSystem {// from your library
2. public:
3 ....
4. std: size_t numDisks () const; // one of the many member functions
5 ....
6 .};
7. extern FileSystem tfs; // the object to be used by the customer. tfs stands for "the file system"
Assume that some customers have set up a class to process the directory (directories) in the file system ). Naturally, their class will use theFileSystem objects:

1. class Directory {// created by the library Client
2. public:
3. Directory (params );
4 ....
5 .};
6. Directory: Directory (params)
7 .{
8 ....
9. std: size_t disks = tfs. numDisks (); // use a tfs object
10 ....
11 .}
Further assume that these customers decide to create a Directory object to place temporary files:

1. Directory tempDir (params); // Directory created for temporary files
Unless tfs is initialized before tempDir, The tempDir constructor uses the uninitialized tfs. However, tfs and tempDir are created by different people at different times in different source code files. They are non-local static objects defined in different compilation units.

C ++ does not explicitly define the initialization order of "non-localstatic objects defined in different compilation units. There is a reason for this: it is very difficult, very difficult, and there is no solution to determine their initialization order.

A small design can completely eliminate this problem: Move each non-localstatic object to its own exclusive function and declare the object as static in this function, these functions return a reference pointing to the objects contained in it. Then the user calls these functions without directly referring to these objects. In other words, the non-local static object is replaced by the local static object. This is a common implementation method of the Singleton mode.

C ++ ensures that the local static object in the function will be initialized when the definition of the object is first met during the call of the function. If you have never called the "simulation function" of a non-local static object, the constructor and the constructor will never be triggered!

The result is as follows:

1. class FileSystem {...}; // same as before
2. FileSystem & tfs () // This function is used to replace the tfs object.
3. {// FileSystem class may be static.
4. static FileSystem fs; // defines and initializes a local static object,
5. return fs; // return a reference pointing to the above object.
6 .}
7. class Directory {...}; // same as before
8. Directory: Directory (params) // same as before, but the original reference to tfs
9. {// change to tfs ()
10 ....
11. std: size_t disks = tfs (). numDisks ();
12 ....
13 .}
14. Directory & tempDir () // This function is used to replace the tempDir object;
15. {// It may be static in Directory class.
16. static Directory td; // define and initialize the local static object,
17. return td; // return a reference pointing to the above object.
18 .}
After this modification, the only difference between the customers of this system program is that they are using tfs () and tempDir () instead of tfs and tempDir, that is to say, they use the references "pointing to static objects" returned by the function, instead of using the static object itself. The fact that these functions contain static objects makes them uncertain in multithreaded systems.

L to avoid the issue of "initialization order across compilation units", replace the non-local static object with the local static object.

 
From pandawuwyj's column

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.