Does C++ call destructors for global and class static variables? - c++

From my example program, it looks like it does call the destructors in both the cases. At what point does it call the destructors for global and class-static variables since they should be allocated in the data section of the program stack?

From § 3.6.3 of the C++03 standard:
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 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. For an object of array or class type, all subobjects of that object are destroyed before any local object with static storage duration initialized during the construction of the sub- objects is destroyed.
Furthermore, § 9.4.2 7 states:
Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).
However, if a destructor has no observable behavior, it may not be invoked. Terry Mahaffey details this in his answer to "Is a C++ destructor guaranteed not to be called until the end of the block?" .

Somewhere after "main"
(you can't know or rely on the exact order in which they are called)

Related

Why is the destructor called for an object that is not deleted?

struct A
{
~A() = delete;
};
int main()
{
new A{};
}
This fails to compile with error message:
error: use of deleted function 'A::~A()'
new A{};
As I understand I'm not destroying the object so why is it trying to call the destructor?
Compiled with
GCC 8.1.0
g++ -std=c++17 -O2
This is gcc bug 57082.
Let's go from the bottom up.
[dcl.fct.def.delete]/2:
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
Clearly, we're not referring to ~A() explicitly. Are we referring to it implicitly? [class.dtor]/12:
A destructor is invoked implicitly
for a constructed object with static storage duration ([basic.stc.static]) at program termination ([basic.start.term]),
for a constructed object with thread storage duration ([basic.stc.thread]) at thread exit,
for a constructed object with automatic storage duration ([basic.stc.auto]) when the block in which an object is created exits ([stmt.dcl]),
for a constructed temporary object when its lifetime ends ([conv.rval], [class.temporary]).
Or in [expr.new]/20:
If the new-expression creates an array of objects of class type, the destructor is potentially invoked.
Do we have any of those things? No, there is no object with automatic, static, or thread storage duration here, nor is there a constructed temporary object, nor is our new-expression creating an array. There is only one object here at all, the one A with dynamic storage duration that we're aggregate-initializing.
Since we're neither explicitly nor implicitly referring to ~A(), we can't be tripping over that rule. Hence, gcc bug. Note also that gcc accepts new A; and new A();, which have the same meaning as far as this rule is concerned.
Probably a gcc bug here.
The standard specifies that the destructor is potentially invoked when the new expression create an array [expr.new]:
If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function, and the constructor.
If the new-expression creates an array of objects of class type, the destructor is potentially invoked.
emphasis mine
gcc applies also this rule when creating a non array, which is implicitly not a standard rule. Thanks to below comments it seems gcc do the exact opposite: when creating a non array, it considers the destructor to be potentialy invoked and when creating an array it just don't check the destructor.
As far as I can tell, no objects are destroyed in the example, and it happens to compile if the expression is changed to new A;
I think that the example code not compiling is is a bug in GCC. Clang compiles it just fine.
Answer for the newly added language-lawyer tag.
The crucial standard rule is this in [class.dtor]:
A destructor is invoked implicitly
... cases that don't apply involving other storage durations than dynamic ...
... A destructor
is also invoked implicitly through use of a delete-expression (5.3.5) for a constructed object allocated by
a new-expression (5.3.4); the context of the invocation is the delete-expression. [ Note: An array of class
type contains several subobjects for each of which the destructor is invoked. — end note ] A destructor can
also be invoked explicitly. A destructor is potentially invoked if it is invoked or as specified in 5.3.4, 12.6.2,
and 15.1.
5.3.4 is [expr.new] which only specifies
... If the
new-expression creates an array of objects of class type, the destructor is potentially invoked (12.4).
which doesn't apply.
12.6.2 is [class.base.init] which only specifies
In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is
potentially invoked (12.4).
Which doesn't apply
15.1 is [except.throw] which specifies how an exception object is destroyed, which doesn't apply
Conclusion: None of sections 5.3.4, 12.6.2, and 15.1. contain a rule that applies to this case, and the destructor isn't invoked, nor is there a delete-expression. Therefore the destructor isn't potentially invoked, so it is well formed for the destructor to be deleted.

What does it mean for an object to exist in C++?

[class.dtor]/15 reads, emphasis mine:
Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8).
However, as far as I can tell, this is the only reference in the standard to an object "existing." This also seems to contrast with [basic.life], which is more specific:
The lifetime of an object of type T ends when:
if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
the storage which the object occupies is reused or released.
We have two different wordings here: "the lifetime of an object ends" and "the object no longer exists," the former only happens with a non-trivial destructor and the latter happens with any destructor. What is the significance of the difference? What is the implication of an object no longer existing?
The quoted wording would seem to imply that a compiler could correctly insert code that returns the memory associated with an object to the heap at the beginning of its destructor. But doing that would eliminate the ability of an object to reference its own members during destruction, which is required if an object is to be able to destroy itself.
So I think the quoted wording is broken and should be fixed.
Concerning what "lifetime" and "existence" mean, I propose that there are some different contexts, in which they mean different things:
Within the context of construction, lifetime and existence begin when a constructor begins. Outside that context, they begin when a constructor ends.
Within the context of destruction, lifetime and existence end when a destructor ends. Outside that context, they end when destruction begins.
So an object may refer to its own members during construction, and potentially pass itself to functions of other objects, which may refer to the object and its members, and so on. But in general, objects (instances of classes) may not be referenced (without producing undefined behavior) until after one of their constructors has finished.
And an object's destructor may refer to its own members and call functions of other (existing) objects, which may refer to the object being destroyed and/or its members. But in general, an object may not be referenced after its destructor has started.
This sort of multi-contextual definition is what makes the most sense to me, but I can see arguments being made that an object should be considered to be alive from the moment memory is allocated for it to the moment that memory is released, and I would say memory for a shallow copy should be allocated for an object when one of its constructors starts, and released when its destructor ends.

Why are the fields of the class automatic objects?

During my studing exeption's mechanism I found that there are calls of destructors for fields of the object while stack's unwinding. Let me explain explicitly:
class X
{
File_ptr aa;
Lock_ptr bb;
public:
X(const char* x,const char* y):aa(x),bb(y){}
//.......
}
So,now if Lock_ptr's constructor throws an exeption, object aa will be destroyed;
The question is "why"? I always thought that fileds of the object are not usual automatic (lochal) objects.They are created before constructor initializes them.So they can't be destryed after they're out of scope of constructor (Otherwise they would be destroyed as soon as constructor's finished its work)
Subobjects (including non-static data members) have the same storage duration as the complete objects to which they belong. This is not the same as saying that they are automatic. An automatic object is destroyed at the end of a block. A subobject is destroyed whenever its complete object is destroyed. For example, if the complete object is created with new and destroyed with delete (i.e. has dynamic storage duration), then the subobject is also created in the call to new, and destroyed in the call to delete. On the other hand, a subobject of an automatic object is also automatic.
If the constructor for X::bb throws an exception, then it means the complete object of type X cannot be constructed. All subobjects that have already been constructed, such as X::aa, must be destroyed, because a subobject, having the same storage duration as its complete object, cannot survive without the complete object.
On the other hand, if construction of the entire X object completes successfully, X::aa and other subobjects won't be destroyed until (shortly after) the complete X object is destroyed.
The construction and destruction rules for C++ are intended to guarantee that, as long as a program terminates normally, every object that is created is also destroyed exactly once. This is essential for the RAII idiom. In this example, if X::aa acquires resources when it is constructed, the language must ensure that those resources will be released. If X::aa's destructor is not called when construction of the X fails, then when should it be called?
X has a "real" constructor that constructs aa and bb, and then after that the constructor body of X is called. This is why the initializer list is before X's constructor "body". Inside of this "real" constructor, the bases and then members are created as if they were on the stack in the order they're declared in the class, including for stack unwinding. I even have a picture:
Destructors work on a vaguely similar principle, except in reverse, but can be even more complicated if the destructor is virtual. If the destructor is virtual, then there's three parts. There's a "stub" destructor that gets called when someone calls the destructor, which dispatches to the most-derived type's "real" destructor. The "real" destructor calls your destructor "body", and then destructs the members in the reverse order that they're declared in the class, and then it destructs the base classes (still in reverse order, same as a stack).
*QuestionC correctly observes that static members are completely independent of everything I wrote here.
Member objects (unless they are static) are constructed when the class constructor is called. The behavior you are seeing is normal and correct.
Member objects are not destroyed when the constructor is finished. They are destroyed when the class destructor is called (in reverse order of construction).

Does C++11 core language takes care of Singleton Dead Reference?

I have recently read Andrei Alexandrescu's Modern C++ Design. After reading 6. chapter, I begin to worry about our singletons at company. Since our experienced team leader writes core helper libraries like singletons etc... . I asked him if the way he handles singleton takes care of on dead reference problem ? If he used at_exit function call which is given by C core language?
He told me C++11 has singleton support and will execute CTORs and DTORs in a row that they will not be any dead reference problem. User will not have to cope with synchronization.
Even it sounds awesome I couldn't find any information which confirms him on internet. So please tell me if C++11 takes care of Dead Reference Problem for singletons and if so please explain a little what dark magic going behind ?
Presumably your team leader is talking about singletons implemented as follows:
T &get_value() {
static T val;
return val;
}
In this case, the standard gives two guarantees. The first is that the val objects will be constructed exactly once, the first time that the flow of program execution passes the declaration of the local static variable, even if that happens simultaneously on several threads 6.7/4:
An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
Static initialisation is only allowed in the case of constants, so as long as T does not have a constexpr constructor you shouldn't have to worry (but read 3.6.2 for the full rules, in case there is some edge case that is relevant to your code).
The second guarantee is that all variables with static storage duration will be destructed in the reverse order of their construction 3.6.3/1:
Destructors (12.4) for initialized objects (that is, objects whose lifetime (3.8) has begun) with static storage duration are called as a result of returning from main and as a result of calling std::exit (18.5). Destructors for initialized objects with thread storage duration within a given thread are called as a result of returning from the initial function of that thread and as a result of that thread calling std::exit. The completions of the destructors for all initialized objects with thread storage duration within that thread are sequenced before the initiation of the destructors of any object with static storage duration. If the completion of the constructor or dynamic initialization of an object with thread storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first. If the completion of the constructor or dynamic initialization of an object with static storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first. [Note: This definition permits concurrent destruction. — end note ] If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized. For an object of array or class type, all subobjects of that object are destroyed before any block-scope object with static storage duration initialized during the construction of the subobjects is destroyed. If the destruction of an object with static or thread storage duration exits via an exception, std::terminate is called (15.5.1).
While this paragraph gives a lot of scope for concurrent destruction of static objects when their construction was concurrent, the main thing to take away from it is that destruction happens in the reverse order of construction.
Together, these mean means that if T val depends on some U val in another of these singleton functions, the U val will always be constructed before T val and destructed after the T val, so overall, this is a safe way of implementing singletons (unless you're doing something very crazy).

Lifetime of object is over before destructor is called?

I don't understand this:
3.8/1 "The lifetime of an object of type T ends when: — if T is a class type with a non-trivial destructor (12.4), the destructor call
starts, or — the storage which the object occupies is reused or
released."
If the lifetime ends before the destructor starts, doesn't that mean accessing members in the destructor is undefined behavior?
I saw this quote too:
12.7 "For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor
finishes execution results in undefined behavior."
But it doesn't make clear what's allowed during the destructor.
If the lifetime ends before the destructor starts, doesn't that mean accessing members in the destructor is undefined behavior?
Hopefully not:
From N3242 Construction and destruction [class.cdtor] /3
To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
The "lifetime" of an object is relevant for consumers of the object, not the object itself. Therefore a consuming class should not attempt to access members of an object once destruction has started.
No, there's no problem:
Member objects come alive before a constructor body runs, and they stay alive until after the destructor finishes. Therefore, you can refer to member objects in the constructor and the destructor.
The object itself doesn't come alive until after its own constructor finishes, and it dies as soon as its destructor starts execution. But that's only as far as the outside world is concerned. Constructors and destructors may still refer to member objects.
"Lifetime" doesn't mean that. It is a precisely defined term in the standard that has a variety of implications, but it might not have all the implications that you would think. Members can still be used during construction and destruction, outside code can call member functions, etc, etc.
Granted, it's a bit odd for client code to call member functions concurrently with the destructor, but not unheard of and certainly not disallowed by the language. In particular, std::condition_variable explicitly allows the destructor to be invoked while there are outstanding calls to condition_variable::wait(). It only prohibits new calls to wait() after the destructor starts.