Can static allocated memory become invalid during

2019-05-27 08:56发布

问题:

Say I have defined a variable like this (C++):

static const char str[] = "Here is some string data";

And I have a statically allocated class instance which references this array in its destructor, can this go wrong? E.g. could the str variable somehow get invalid?

class A {
 ~A() {
   cout << str << endl;
 }
};

static A a;

My assumption is that it can't go wrong, but I can find it clearly stated anywhere. I want to know this for sure. My assumption is that we can not predict the sequence in which destructors for statically allocated objects are called but that the data itself is never really freed until the process is torn down. Meaning pointers to POD should be safe, but not object instances.

Meaning e.g. this:

static const QString str = "Here is some string data";

or

static const std::string str = "Here is some string data";

Can not safely be used in A's destructor because they both allocate their string data on the heap and this might be freed by the destructor before A's destructor is called.

Is my assumption right and are there any sections in the C++ standard explaining this or some link to some other authority who can verify this?

回答1:

The order in which destructors for automatic, global, and static objects are called is always well defined: it's the reverse of the order in which the constructors were called. So if object A references an object B and B was constructed before A, you can be sure that B is destructed after A. That leaves us with the question of the order of constructors.

Here's what I remember:

  1. Global and static objects are constructed before main() is called.
  2. Class-local statics are constructed before any object of their class.
  3. Function-local statics are constructed when their scope is reached for the first time.
  4. Global and static objects within the same translation unit are constructed in the order they are defined. (That means that the order of inclusion of headers might affect this!)
  5. The order of construction of global and static objects across translation units is undefined.

I'm a bit hazy on some of these, so please correct me if you think this isn't right.



回答2:

Okay I tried to read the C++ standard myself to find some answers. I see from the answers I get that there is a lot of confusion about difference between constructing an object and allocating it.

From the standard:

3.6.2 Initialization of non-local objects

Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. A reference with static storage duration and an object of POD type with static storage duration can be initialized with a constant expression (5.19); this is called constant initialization. Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place. Dynamic initialization of an object is either ordered or unordered.

My interpretatio of this is that a const char[] will always be guaranteed to have been set before any constructor is run.

3.6.3 Termination Destructors (12.4) for initialized objects of static storage duration (declared at block scope or at namespace scope) are called as a result of returning from main and as a result of calling std::exit (18.3). These objects are destroyed in the reverse order of the completion of their constructor or of the completion of their dynamic initialization. If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized.

From what I can read from this POD types with constant expression will be initialized before any object types and destroyed after any object types. Meaning no code will run that can access them while they are not valid.

Which should explain why Google's C++ code standard says you should only use POD types with constant expressions.:

As a result we only allow static variables to contain POD data. This rule completely disallows vector (use C arrays instead), or string (use const char []).



回答3:

If I remember correctly, global object initialization is not defined in the standard (or poorly defined) making global objects hard to reference each other.

If you want to be sure about initialization order, use a global function with your static object in it, that just return it. You're now garanteed that the static object will be initialized on first function call.

Destruction will occur at the end of the application, once out of main().