1

Question coming from another question I recently asked Referencing a possibly destroyed static object. Can a destructor for an instance of a class use a global primitive variable/constant? Is it guaranteed to hold its value till program termination (i.e. after the statics have been destroyed)?

I know that static object destruction across compilation units is not defined but I was wondering whether the same holds for primitive values.

For example

Something.cpp

extern bool global_boolean_value;

Something::~Something() {
    assert(global_boolean_value);
}
Community
  • 1
  • 1
Curious
  • 20,870
  • 8
  • 61
  • 146
  • related/dupe: http://stackoverflow.com/questions/12728535/will-global-static-variables-be-destroyed-at-program-end – NathanOliver Jan 05 '17 at 14:59
  • @NathanOliver I think both those questions ask about class objects? Or is there something that I missed – Curious Jan 05 '17 at 15:04
  • AFAIK there is not difference between how a global `int` is destroyed versus a global `foo`. – NathanOliver Jan 05 '17 at 15:06
  • 4
    If the answer to this question was UB, wouldn't it mean that one cannot access `errno` (and similar stuff) in the destructor? – A.S.H Jan 05 '17 at 15:09
  • Related: http://stackoverflow.com/questions/305554/c-do-static-primitives-become-invalid-at-program-exit - According to the first answer here, this is valid. – Holt Jan 05 '17 at 15:19
  • 2
    Globals are not allocated on stack or heap. There is a piece of static (in the sense of size) memory given to the process by OS (data segment) where globals live. The OS takes care of freeing this memory after process exits. So anything that is there is available all the time, even after all destructors fire. Of course destructors may corrupt those objects but the memory is still there. And since primitives don't have destructors then accessing things like `errno` should be safe. Although I'm not 100% sure if this is UB or not. – freakish Jan 05 '17 at 15:30
  • @freakish I wonder if the standard says something about this.. – Curious Jan 05 '17 at 15:36
  • @Curious Now that I think about it, it might be OS dependent. I couldn't find any relevant info in the standard unfortunately. :( – freakish Jan 05 '17 at 16:16

1 Answers1

2

With respect to initialization the standard lumps together everything with "static storage duration", which are the variables (including member variables) declared using the static keyword (variables with internal linkage) as well as "true globals" (variables with external linkage). The standard does not distinguish between plain old data types one one hand and structs or classes on the other.

Note after comments (all quotes from the 2012 standard):

3.7.1 Static storage duration [basic.stc.static]
1   All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3).

(Emphasis by me.) There is no distinction between PODs and non-PODs. Note that the paragraph defines the lifetime of the storage, not of the (typed, initialized) object. When the program (not main()!) starts, all static storage is readily allocated. And yes, the destructors of objects with static storage duration are part of the program. This makes it, as far as I can see, safe to access errno in a destructor.

As you say, there is no guarantee about the order of initialization of objects with static storage duration across different translation units; within one TU the initialization is performed in the definition order, and destruction is then done in the opposite order.

That is all there is to it (apart from workarounds, like putting your globals in an artificial class or returning static local variables from functions).

The answer to your example question then depends on the storage duration of the object for which the destructor is called. If the object has static storage duration and is in a different translation unit, you are out of luck. If it is automatically or dynamically allocated, or if it is defined in the same translation unit after the global variable you are fine.

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • 1
    Could you comment on `errno` case mentioned by A.S.H. in comments? If I understood you well, it's guaranteed to be in the `out of luck` territory? But then.. runtime libs are unloaded last I suppose? – quetzalcoatl Jan 05 '17 at 15:21
  • 2
    @quetzalcoatl Somewhat hairy. Of course I'll bet 100 dollars to one that `errno` is ok to access in the dtor of a static. There are a few points to consider. (1) the stdlib is not written in C++. No ctors, no dtors. Does the C++ run time "create" global objects in dlls? There is no allocation necessary, only initialization. Who does that? These arcane C++ rules may not apply at all. (2) We are probably executing a stdlib function (like, `exit()`). The library cannot have been unloaded yet. (That possibility is the rationale for the non-ordering across TUs.) – Peter - Reinstate Monica Jan 05 '17 at 15:37
  • 1
    *"The standard does not distinguish between plain old data types one one hand and structs or classes on the other."* - That is not really true. There is a difference regarding the end of their lifetimes (if a type as a non-trivial destructor or not). The lifetime of an object with primitive type and static storage duration will last for the duration of the program, while the lifetime of an object with a type with a non-trivial destructor and static storage duration will end when this destructor is called. [...] – Holt Jan 05 '17 at 16:32
  • 1
    Since the destructor execution of any object with static storage duration is part of the program duration (I think?), then the lifetimes of objects with primitive type and static storage duration will include the destructor execution, thus making it perfectly valid to use the object inside. – Holt Jan 05 '17 at 16:32
  • @Holt If only the standard clarified this.... I am unable to find any convincing information anywhere other than your argument – Curious Jan 05 '17 at 16:37