Home > Enterprise >  Using the keyword 'new' in file scope?
Using the keyword 'new' in file scope?

Time:12-02

Given this class in the header file:

class ClassA
{
public:
ClassA(){};
}

Then in file.cpp

#include file.h
ClassA* GlobalPointerToClassAType = new ClassA();

a. Is it allowed, and is it good practice to use the keyword 'new' to allocate memory for an object in the heap(?) in lines of file-scope?

b. If it is allowed, then when exactly does the constructor ClassA() is actually called?

c. How does it differ if I wrote instead this line:

ClassA GlobalInstanceOfClassAType = ClassA();

in terms of the time of calling the constructor, in terms of memory efficiency, and in terms of good practice?

CodePudding user response:

a. Is it allowed, and is it good practice to use the keyword 'new' to allocate memory for an object in the heap(?) in lines of file-scope?

It is allowed. Whether is it good practice to use new here is opinion based. And i predict that most people will answer no.


b. If it is allowed, then when exactly does the constructor ClassA() is actually called?

Let's start from some concepts.

In C , all objects in a program have one of the following storage durations:

  • automatic
  • static
  • thread (since C 11)
  • dynamic

And if you check the cppreference, it claim:

static storage duration. The storage for the object is allocated when the program begins and deallocated when the program ends. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration, plus those declared with static or extern. See Non-local variables and Static local variables for details on initialization of objects with this storage duration.

So, GlobalPointerToClassAType has static storage duration, it fit the statement that "All objects declared at namespace scope (including global namespace) have this storage duration...".

And if you get deeper into the link of the above section, you will find:

All non-local variables with static storage duration are initialized as part of program startup, before the execution of the main function begins (unless deferred, see below). All non-local variables with thread-local storage duration are initialized as part of thread launch, sequenced-before the execution of the thread function begins. For both of these classes of variables, initialization occurs in two distinct stages:

There's more detail in the same site, you can go deeper if you want to get more, but for this question, let's only focus on the initialization time. According to the reference, The constructor ClassA() might be called before the execution of the main function begins (unless deferred).

What is "deferred"? The answer is in the below sections:

It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.

If the initialization of a non-inline variable (since C 17) is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library). However, as long as anything from a translation unit is odr-used, all non-local variables whose initialization or destruction has side effects will be initialized even if they are not used in the program.

Let's see a tiny example, from godbolt. I use clang, directly copy your code, except that the Class A and main are defined in the same translation unit. You can see clang generate some section like __cxx_global_var_init, where the class ctor is called.

  • Related