6.1 Construction and deconstruction of objects (object construction and destruction)
generally, constructor and destructor are inserted as expected:
{point point ; Point. Point::P oint () is generally inserted here ... Point. Point:;~point () is generally inserted here}
If there is more than one exit point in a section (the area enclosed in {}) or a function, the situation is a little bit confusing. destructor must be placed at each exit point (when object is still alive), for example:
{point point ; constructor here action switch (int (point.x ())) { case-1: //mumble //destructor Act here return;< C13/>case 1: ///mumble //destructor here to return to action; Default: //mumble //destructor here action return; } destructor here to act}
In this example, the destructor of point must be generated before the return operation of the switch command four exits, plus
It is also likely to be generated before the end symbol (the closing brace) of this section-even if the results of the program's analysis are found to be absolutely not there ..
Similarly, a goto instruction may require many destructor invoke operations. For example, the following program fragment:
{if (cache2) //check the cache; if it matches, return 1 return 1; Point xx; The constructor of XX acts here while (Cvs.iter (XX)) if (xx = = value) goto found; XX's destructor here action return 0;found: //cache item //xx destructor here action return 1;}
The destructor call operation must precede the last two return instructions, but it does not have to be placed before the original return, since the object is not yet defined.
It is generally possible to place the object in the vicinity of the program section where it is used, which saves unnecessary object generation operations and destruction operations .In this case, if point object is defined before the cache is checked, it seems quite obvious, but many Pascal or C programmers use C + + and are still accustomed to putting all objects at the beginning of a function or section.
Global Objects If you have the following program fragments:
Matrix Identity;main () { //identity must be initialized here in matrix m1 = identity; ... return 0;}
C + + guarantees that the identity must be constructed before the identity is first used in the main () function, and the identity is destroyed before the main () function endsThe so-called global object, such as identity, requires a static initialization operation and a memory release operation if it has constructor or destructor.
all global objects in a C + + program are placed in the program's data segment. If you explicitly assign it a value, object will be the initial value. Otherwise, the memory content that object is configured to is 0.So in the following code:
int v1 = 1024;int v2;
V1 and v2 are configured in the program's data segment,v1 value is 1024,v2 value of 0 (this is slightly different from C, C does not automatically set the initial value). In C, a global object can only be set as an initial value by a constant expression that can be evaluated at compile time. Of course, constructor is not a constant expression. Although class object can be placed in data segment at compile time and the content is 0, constructor is not implemented until program activation (startup). Must have a " The initialization expression for object placed in program data segment is evaluated, which is why an object requires static initialization.
When Cfront is still the only C + + compiler, and when cross-platform portability is more important than efficiency considerations, there is a portable but costly static initialization (and memory-freeing) approach. Cfront's bondage is, Its solution must be valid on every UNIX platform. Therefore, no assumptions can be made beforehand, either in the relevant linker or object-file format. Because of this limitation, the following strategy emerges:
1. Generate a _sti () function for each file that needs to be statically initialized, with the necessary constructor call operations or inline expansions. For example, the identity object mentioned earlier will produce the following _sti () function in matrix.c ( STI may be the abbreviation for static initialization):
__sti__matrix_c__identity () { identity. Matrix::matrix (); This is static initialization}
Where Matrix_c is the file name encoding, _identity represents the first static object defined in the file. Append these two names after __sti to provide a unique identifier for the executable file.
2. Similarly, in each filegroup macro that requires a static memory release operation (Static deallocation), a __std () function (Std may be an abbreviation for the static deallocation) is produced. With the necessary destructor call operation, or its inline expansions. In the example, a __std () function is generated to call the Matrix destructor for the identity object.
3. Provide a set of runtime library "Munch" functions: a _main () function (to invoke all the __sti () functions in the executable file), and an exit () function (which invokes all __STD () functions in a similar way).
As shown (direct excerpt from the book p244 original):
Cfront inserts a _main () function call operation in the program, the first instruction of the main () function. Unlike the exit () of the C library, in order to link the former, the C + + standard must first be specified in the CC command of the Cfront Library.
The last question to be solved is how to collect the __sti () function and the __STD () function of each object files in a program. It must be portable. At the time, Cfront (also on behalf of C + +) would have to rely on it to succeed in being popular on UNIX platforms.
The workaround is to use the NM command. NM will print out the symbol table item for the object file (symbol table entries). An executable file system is generated by an. o file, and NM will be executed on the executable file. Its output is imported into the Munch program. The Munch program searches for a name that starts with __sti or __STD, but adds the function name to a jump table for the STI () function and the STD () function, which then writes the table to a small programs Text file, the file containing the table is compiled, and then the entire executable is re-linked, _main () and exit () are then accessed over each table, and each item is called in turn (representing a function address).
The local static Objects is assumed to have the following program fragments:
Const Matrix &identity () { static matrix mat_identity; // ... return mat_identity;}
What kind of semantics does Local static class object guarantee?
Mat_identity's constructor must be performed only once, although the above function may be called multiple times.
Mat_identity's destructor must be performed only once, although the above function may be called multiple times.
One of the compiler's policies is to construct the object unconditionally at the start of the program, but this causes all local static class objects to be initialized at the beginning of the program, even if the function they are in is never called. It is a good practice to construct the mat_identity only when the identity () is called.
first, a temporary object is imported to protect the initialization of the mat_identity. When the identity () is processed for the first time, the temporary object is evaluated to false, so constructor is called and the temporary object is changed to True. This solves the problem of construction ., and at the opposite end, destructor also needs to be conditionally carried out with mat_identity, but only when mat_identity has been constructed. To determine if mat_identity is constructed, it is simple,
if the temporary object is true, it means that it is well constructed. The difficulty is that because Cfront generates C code, mat_identity is still local to the function, so there is no way to access it in a static memory-releasing function (static deallocation functions). The solution is:
Remove the address of the local object(Because object is static and its address is converted to the data segment within the program to place the global object in downstream component), the following is the output of Cfront:
The resulting temporary object, as the static struct Matrix *__0__f3 = 0;//C + + reference in C with pointer instead of/identity () will be mangledstruct Matrix *IDENTITY_FV () { static struct Matrix __lmat_identity; If the temporary protection object has been established, do nothing, otherwise //A. Call CONSTRUCTOR:__CT__6MATRIXFV //b. Set the protection object so that it points to the target object __0__f3? 0 (__ct__ 6MatrixFv (&__lmat_identity), (__0__f3 = (&__lmat__identity)));}
Finally, the destructor must be conditionally called in the static memory deallocation function that is associated with the text program file. deallocation.
The object array (array of Objects) assumes the following array definitions:
Point KNOTS[10];
What needs to be done? If point neither defines a constructor nor defines a destructor, then the work is no more than building an array of "built-in (build-in)" types, which means that Just configure enough memory to store 10 contiguous point elements.
However, point does define a default destructor, so this destructor must be performed on each element in turn. This is generally achieved through one or more runtime library functions. In Cfront, A function named Vec_new () is used to produce an array constructed from class objects. The new compiler provides two functions to handle the "no virtual base class" class, and the other to handle the "inner virtual The class of base class. The latter function is often referred to as
vec_vnect. Function types are usually as follows:
void *vec_new () { void *array, //array start address size_t elem_size, //size of each class object int elem_count; Number of elements in array void (*constructor) (void *), Void (*destruction) (void *, char)}
where the constructor and destructor parameters are the default construct and default destructor function pointers for this class.
Parameter array with not a named array(This example is knots)
the Address, which is 0. If 0, the array is dynamically configured in the heap via the application's new operator.
The parameter elem_size represents the size of the element in the array (the number of elements translated into the book may be incorrect)In Vec_new, constructor is performed on Elem_count elements. For compilers that support exception handling, The provision of destructor is necessary. The following is a vec_new () call operation that the compiler might make for 10 point elements:
Point Knots[10];vec_new (&knots, sizeof (point), &point::P oint, 0);
If point also defines a destructor, when Knots's life ends, the destructor must also be performed on the 10-element. This is a similar
Vec_delete ()The runtime library function is completed, and its
The function type is as follows:
void *vec_delete{ void *array, //array start address size_t elem_size, //size of each class object int Elem_count, the number of elements in the//array void (*destructor) (void *, char)}
Some compilers add additional parameters to pass other values so that the logic of Vec_delete () can be conditionally guided, and in Vec_delete (), destructor is performed on Elem_count elements.
What if the programmer provided one or more explicit initial values to an array of class objects, like so?
Point knots[10] = {Point , point (1.0, 1.0, 0.5), -1.0};
Vec_new is no longer necessary for those elements that have an obvious initial value. For those elements that have not yet been initialized, Vec_new () is performed as if it were an array of class elements, and the array has no explicit initialization List, so the previous definition is likely to be converted to:
Point knots[10];//explicitly initializes the first 3 elements of point::P oint (&knots[0]); Point::P oint (&knots[1], 1.0, 1.0, 0.5); Point::P oint (&knots[2],-1.0, 0.0, 0.0);//Vec_new after initialization 7 elements vec_new (&knots+3, sizeof (point), 7, &point:: Point, 0);
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
C + + object model--object construction and Deconstruction (sixth chapter)