Effective C ++ 2e Item47

zhaozj2021-02-11  191

Terms 47: Ensure that non-local static objects are initialized before use

Everyone is an adult, so I don't need me to tell you: It is not very different from the object that is not initialized. In fact, the entire idea about this problem will make you feel ridiculous; the constructor can ensure that the object is initialized when it is created, isn't it the case?

Oh, yes, nor. In a particular compiler (ie, source file), it may not be a problem. However, if in a compilation unit, an object's initialization is dependent on another object in another compilation unit. Value, and this second object itself also needs to be initialized, and things will become more complicated.

For example, suppose you have written such a library that provides an abstraction of a file system, which may include a function that makes the files on the Internet look like locally. Since the library makes the entire world look like a separate file system, you can create a dedicated object in the name space of the library (see Terms 28), ThefileSystem, this, the user needs to provide with the library any time. File system interaction, you can use it:

Class filesystem {...}; // In a class in your // library

FileSystem thefilesystem; // Library User / / And this object interact

Because theFileSystem represents a very complicated thing, it is important and necessary; it will cause unsure behavior before theFileSystem has not been constructed. (However, the reference clause M17, like the object such as TheFileSystem, its initialization can be valid, safely delayed.)

Now suppose users of a library created a class to represent the directory in the file system. Naturally, this class uses thefilesystem:

Class Directory {// Create a public: directory (); ...};

Directory :: Directory () {Create a Directory object by calling the Filesystem's member function;}

Further hypothesize that users want to create a global Directory object for temporary files:

Directory Tempdir; // Temporary Directory

The problem of initialization is now clear: unless the FileSystem is initialized before Tempdir, the Tempdir constructor will go to the ThefileSystem that has not been initialized yet. But ThefileSystem and Tempdir are created by different people at different times, different files. How can I confirm that thefilesystem is created before Tempdir?

At any time, if "non-local static object" is defined in different compiletable units, and the correct behavior of these objects depends on a particular order they are initialized, such issues will be generated. Non-local static objects refer to this object:

• Define within a global or name spatial range (for example: thefilesystem, and tempdir), which is declared in a class as static, or • On a file range is defined as static.

Sorry, "Non-local static objects" is not referred to as this term, so you have to let yourself get used to this bit of joking sentence. For non-local static objects in different compiled units, you must not want our program behavior to rely on their initialization order because you can't control this order. Let me repeat again: you absolutely unable to control the initialization sequence of non-local static objects in different compilation units.

I naturally want to know, why can't you control?

This is because it is difficult to determine the "correct" order of the initialized non-local static objects, very difficult, extremely difficult. Even in its most common form - multiple compiletable units, multiple compiletable units, multiple types of non-local static objects generated by implicit templates (I can instantiate the implicit template, they may have such problems) ---- Not only impossible to determine the correct initial order, it is often not worth it to find a special case that can determine the correct order.

In the field of "chaos theory", there is a principle called "butterfly effect". This principle claims that a butterfly on a corner of the world will make wings to produce a small impact on the atmosphere, resulting in a deep change in a distant local weather mode. A slightly accurate point is: For some kind of system, the input micro-interference will result in a thorough change.

The development of software systems also expressed their own "butterfly effect". Some systems are highly sensitive to demand, and the demand changes, and the difficulty of realization of the system will have a huge change. For example, clause 29 describes that a implicit conversion is changed from "String to Char *" to "String to Const Char *", you can run a slower, easy error, function, fast and secure functions instead.

Make sure that non-local static objects are initialized before use, it is very sensitive to your implementation details. However, if you don't want to access the "non-local static object", it is willing to access objects with non-local static objects "similar behavior" (there is no initialization problem), and the problem disappears. Instead, a problem that is easy to solve is even not a problem.

This technology --- is sometimes referred to as "single mode" (Singleton Pattern, see "DESIGN PATTERNS" book) - itself is simple. First, transfer each non-local static object to a function, declare it for static. Second, let the function returns the reference to this object. In this way, the user will specify the object through a function call. In other words, the Static object inside the function replaces the non-local static object. (See the Terms M26)

This method is based on the fact that although the "non-local" static object is initialized, C has almost not explained; but when the static object in the function (ie, "local" static object) is initialized, C is It is clear that they are initialized when they first touched the object during the function call. So, if you don't directly access the non-local static object, use the function call to the local static object reference to the function call to the local static object, to ensure that the reference from the function points to the object being initialized. Another benefit of doing this is that if the function of this simulated non-local static object never calls, it will never lead to the overhead of object constructing and destruction; and there is no such a good thing for non-local static objects.

Both the following code use this technology to thefilesystem and tempdir: class filesystem {...}; // The FileSystem & theFileSystem () // This function replaces the {// thefilesystem object

Static FileSystem TFS; // Definition and Initialization / / Local Static Object // (TFS = "The File System")

Return TFS; // Return to its reference}

Class Directory {...}; //

Directory :: Directory () {with thefilesystem () instead of thefilesystem ()

Directory & Tempdir () // This function replaces {// tempdir object

Static Directory TD; / / Definition and Initialization / / Local Static Object

Return Td; // Returns its reference}

After the system is modified, the user is still completely programmed as before, but now they use thefilesystem () and tempdir () instead of theFileSystem and Tempdir. That is, what they use is a function that returns an object reference, not an object itself.

Although the function of this return reference has adopted the technique discussed above, the function itself is always very simple: the first line defines and initializes a local static object, and the second line returns it, this is only. Because it is too simple, you may want to declare it as inline. Terms 33 pointed out that for the latest revisions of C language specification, this is a very effective implementation policy; but it also points out that before use, you must confirm that the relevant requirements in your compiler and standard must be consistent. If the compiler does not meet the latest criteria, you can use the inline as the above, it may cause a function and multiple copies of the function within the function. This is enough to make an adult programmer cry.

There is no mysterious place to this. In order to make this technology is valid, it is necessary to give an object a reasonable initialization order. If you let the object A must initialize before the object B, but also let A initialization depend on B has been initialized, you will get trouble, frankly, it is a sin. If you can avoid this unreasonable situation, the scenarios described in this Territic will help you.

转载请注明原文地址:https://www.9cbs.com/read-4429.html

New Post(0)