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.