In-depth analysis of the calling mechanism of c ++ global constructor and destructor

Source: Internet
Author: User

Call mechanism of c ++ global constructor and destructor

The global variables of C ++ in the console EXE are initialized before Main and cleared after main. The VC compiler, linker, and VC Runtime library code work together to complete this magic. Copy this code to the console program you created, and create and run it:

# Include "stdafx. H"

# Include <iostream>


# Define secname ". CRT $ xcu"

# Pragma section (secname, long, read)


Void cleanup ()

{

STD: cout <"bye" <STD: Endl;

}


Void Init ()

{

// Do anything you want.

STD: cout <"hello" <STD: Endl;

Atexit (cleanup); // register the destructor

}


Typedef void (_ cdecl * _ pvfv )();

_ Declspec (allocate (secname) _ pvfv callb4main [] = {init };


Int main ()

{

STD: cout <"in main" <STD: Endl;

Return 0;

}


Output result:

Hello

In Main

Bye


Strange! You didn't call init and cleanup, but obviously they are called. What is the problem?

We know that the real entry function is maincrtstartup. For our discussion, maincrtstartup can be simplified as follows:

Int _ tmaincrtstartup () // this function will be linked to our EXE and used as the entry point function

{

_ Initterm ();

Int result = Main ();

Exit ();

Return result;

}


// File: CRT \ SRC \ crt0dat. c

Static void _ cdecl _ initterm (_ pvfv * pfbegin, _ pvfv * pfend)

{

While (pfbegin <pfend)

{

If (* pfbegin! = NULL)

(** Pfbegin )();

++ Pfbegin;

}

}

This is where the constructor is called. For every global variable we define, the compiler compiles its constructor call (no matter how many parameters you include) into a piece of code (the signature format is _ pvfv ), this Code also registers the Destructor with atexit (which is very easy for the compiler ). Then put the function pointer of this code into a _ pvfv array. The linker concatenates these _ pvfv arrays into a large array.

The pfbegin in the _ initterm parameter points to the first element of the array, and the pfend points to the last element of the array (always null), so our constructor is called, this is also the working principle of the above magic. The function registered by atexit will be executed after main exit (similar to the _ initterm code) and follow the LIFO principle. Therefore, the Destructor will be called in the reverse order of the constructor.


For non-console EXE and DLL, the situation is similar.


The real portal for any user-state process is kernel32.dll! _ Baseprocessstart @ 4, but this is irrelevant to our discussion.


Reference books:

Programmer self-cultivation-loading, linking and Library

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.