{"id":43823,"date":"2014-10-17T07:00:00","date_gmt":"2014-10-17T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/10\/17\/when-are-global-objects-constructed-and-destructed-by-visual-c\/"},"modified":"2014-10-17T07:00:00","modified_gmt":"2014-10-17T07:00:00","slug":"when-are-global-objects-constructed-and-destructed-by-visual-c","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20141017-00\/?p=43823","title":{"rendered":"When are global objects constructed and destructed by Visual C++?"},"content":{"rendered":"<p>\nToday we&#8217;re going to fill in the following chart:\n<\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\" CELLSPACING=\"0\" CELLPADDING=\"3\">\n<tr>\n<td>When does it run?<\/td>\n<th>Constructor<\/th>\n<th>Destructor<\/th>\n<\/tr>\n<tr>\n<th>Global object in EXE<\/th>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<th>Global object in DLL<\/th>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<\/table>\n<p>\nThe C++ language specification provides some leeway to\nimplementations on when global static objects are constructed.\nIt can construct the object before <code>main<\/code> begins,\nor it construct the object on demand according to complicated rules.\nYou can read [basic.start.init] for the gory details.\n<\/p>\n<p>\nLet&#8217;s assume for the sake of discussion that global static\nobjects are constructed before <code>main<\/code> begins.\n<\/p>\n<p>\nFor global objects in the EXE, constructing them is no big deal\nbecause the C runtime startup code linked into the EXE does\na bunch of preparation before calling the formal entry point,\nbe it <code>main<\/code> or\n<code>wWin&shy;Main<\/code> or whatever.\nAnd part of that preparation is calling constructors for\nglobal objects.\nSince the C runtime startup code is in charge,\nit can construct the objects right there.\n<\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\" CELLSPACING=\"0\" CELLPADDING=\"3\">\n<tr>\n<td>When does it run?<\/td>\n<th>Constructor<\/th>\n<th>Destructor<\/th>\n<\/tr>\n<tr>\n<th>Global object in EXE<\/th>\n<td STYLE=\"color: blue\">C runtime startup code<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<th>Global object in DLL<\/th>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<\/table>\n<p>\nDLLs are similar:\nThe formal <code>Dll&shy;Main<\/code> entry point is not\nthe actual entry point to the DLL.\nInstead, the entry point is a function provided by the C runtime,\nand that function does work before and after calling the\n<code>Dll&shy;Main<\/code> function provided by the application.\nWe saw this earlier when we discussed\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/08\/08\/8841951.aspx\">\nwhat happens if you return <code>FALSE<\/code>\nfrom\n<code>DLL_PROCESS_ATTACH<\/code><\/a>.\n<\/p>\n<p>\nPart of this extra work done by the C runtime library is to\nconstruct DLL globals in <code>DLL_PROCESS_ATTACH<\/code>\nand to destruct them in\n<code>DLL_PROCESS_DETACH<\/code>.\nIn other words, the code conceptually goes like this:\n<\/p>\n<pre>\nBOOL CALLBACK RealDllMain(\n    HINSTANCE hinst, DWORD dwReason, void *pvReserved)\n{\n  ...\n  case DLL_PROCESS_ATTACH:\n   Initialize_C_Runtime_Library();\n   Construct_DLL_Global_Objects();\n   DllMain(hinst, dwReason, pvReserved);\n   ...\n case DLL_PROCESS_DETACH:\n   DllMain(hinst, dwReason, pvReserved);\n   Destruct_DLL_Global_Objects();\n   Uninitialize_C_Runtime_Library();\n   break;\n ...\n}\n<\/pre>\n<p>\nOf course, the actual code is more complicated than this,\nbut that&#8217;s the basic idea.\nWe can fill in two more cells in our table.\n<\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\" CELLSPACING=\"0\" CELLPADDING=\"3\">\n<tr>\n<td>When does it run?<\/td>\n<th>Constructor<\/th>\n<th>Destructor<\/th>\n<\/tr>\n<tr>\n<th>Global object in EXE<\/th>\n<td>C runtime startup code<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<th>Global object in DLL<\/th>\n<td STYLE=\"color: blue\">C runtime <code>DLL_PROCESS_ATTACH<\/code>\n    prior to <code>Dll&shy;Main<\/code><\/td>\n<td STYLE=\"color: blue\">C runtime <code>DLL_PROCESS_DETACH<\/code>\n    after <code>Dll&shy;Main<\/code> returns<\/td>\n<\/tr>\n<\/table>\n<p>\nThe last entry in our table is the tricky one:\nWho triggers the destruction of global objects in the EXE destructed?\nThe C runtime startup code in the EXE is guaranteed to run at process\nstartup, but how does the C runtime cleanup code run?\n<\/p>\n<p>\nThe answer is that the C runtime library\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/10\/16\/10565024.aspx\">\nhires a lackey<\/a>.\nThe hired lackey is the C runtime library DLL\n(for example,\n<code>MSVCR80.DLL<\/code>).\nThe C runtime startup code in the EXE\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/tze57ck3\">\nregisters all the destructors with the C runtime library DLL<\/a>,\nand when the C runtime library DLL gets its\n<code>DLL_PROCESS_DETACH<\/code>,\nit calls all the destructors requested by the EXE.\n<\/p>\n<p>\nThat&#8217;s the final cell in our table.\n<\/p>\n<table BORDER=\"1\" STYLE=\"border-collapse: collapse\" CELLSPACING=\"0\" CELLPADDING=\"3\">\n<tr>\n<td>When does it run?<\/td>\n<th>Constructor<\/th>\n<th>Destructor<\/th>\n<\/tr>\n<tr>\n<th>Global object in EXE<\/th>\n<td>C runtime startup code<\/td>\n<td STYLE=\"color: blue\">C runtime DLL hired lackey<\/td>\n<\/tr>\n<tr>\n<th>Global object in DLL<\/th>\n<td>C runtime <code>DLL_PROCESS_ATTACH<\/code>\n    prior to <code>Dll&shy;Main<\/code><\/td>\n<td>C runtime <code>DLL_PROCESS_DETACH<\/code>\n    after <code>Dll&shy;Main<\/code> returns<\/td>\n<\/tr>\n<\/table>\n<p>\nYou can now answer this customer question and explain the\nobserved behavior:\n<\/p>\n<blockquote CLASS=\"q\"><p>\nIs it okay to call <code>Load&shy;Library<\/code>\nfrom within constructors of global C++ objects inside a DLL?\nCurrently we am seeing weird behavior when doing so.\n<\/p><\/blockquote>\n<p>\nThe customer went on to describe what they were observing.\nTheir DLL has global C++ objects which do the following\noperations in their constructor:\n<\/p>\n<ul>\n<li>Check a setting.\n<li>If the setting is enabled, call\n    <code>Load&shy;Library<\/code> to load a helper DLL,\n    then call a function in the helper DLL,\n    The result of that function call alters the global behavior\n    of the original DLL.<\/p>\n<li>The function in the helper DLL\n    creates a thread\n    then waits for the thread to produce a result.<\/p>\n<li>The helper thread never gets started.\n<\/ul>\n<p>\nResult: Process hangs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re going to fill in the following chart: When does it run? Constructor Destructor Global object in EXE Global object in DLL The C++ language specification provides some leeway to implementations on when global static objects are constructed. It can construct the object before main begins, or it construct the object on demand according [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-43823","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re going to fill in the following chart: When does it run? Constructor Destructor Global object in EXE Global object in DLL The C++ language specification provides some leeway to implementations on when global static objects are constructed. It can construct the object before main begins, or it construct the object on demand according [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=43823"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43823\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=43823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=43823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=43823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}