Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between a trivial ctor (or dtor) and a user defined empty ctor (or dtor)

The C++ standard defines some very specific behaviors when a class has a trivial constructor and/or a trivial destructor.

As an example, as per §3.8/1 of the standard:

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.

So,

  • if an object is not trivialy destructible, any attempt to access members of the object after the destructor is called is UB.
  • if an object is trivialy destructible, attempt to access members of the object after the destructor is called is safe and not UB.

Although this example may not be the best one, it shows that the difference in behavior maybe crucial (UB/non-UB) whether an object is trivialy destructible or not.

§12.4/3 of the Standard states that (to sumerize) a destructor of a class T is trivial if it is implicitely defined, not virtual, and if all base classes and members of class T are trivially destructible.

In my (modest) experience, I never saw any difference, in terms of code generated by the compiler, between :

  • a class with a trivial default ctor and/or a trivial dtor, and
  • a class with a user defined empty ctor and/or a non-virtual user defined empty dtor (as long as the class, its base classes and members classes also have non-virtual dtor user defined empty or trivial)

So, my questions are:

  • In what way a user defined empty ctor/dtor can or cannot be considered as a trivial-like ctor/dtor regarding compiler code generation, optimizations, trade-offs, ...
  • Same question with user defined non-empty ctor/dtor; what rules should follow a code implemented in ctor/dtor to consider them as trivial-like.

My question is not related to standard (please, do not answer the standard states what is a trivial ctor/dtor, so user defined ctor/dtor is not) but to the way compilers deal with user defined ctor/dtor and in what way the behavior of a compiled code may change (or not) compared to trivial ctor/dtor.

like image 332
shrike Avatar asked Jun 09 '16 13:06

shrike


1 Answers

You know the standards better than I, but going on the information you've provided, the standard defines a trivial destructor, but it doesn't define an empty destructor, which would make this question kind of misleading. A trivial destructor is then a special case that compilers can optimize to, and while an empty constructor makes sense to us, it's not something compiler writers have to consider.

Browsing a few SO links:

  • Why Does Default user defined destructors in C++ increases execution time? shows a case where a compiler does act differently for trivial vs. empty destructors. The answer there implies one difference is in exception handling. It doesn't look for an empty constructor because it's not required to, and so handles exceptions as if there was valid code inside the dtor.
  • Will an 'empty' constructor or destructor do the same thing as the generated one? seems to be such a close match to your question that it might be a duplicate. It's better to read it on your own instead of relying on my interpretation, but it makes mention of Microsoft compilers not being able to inline empty destructors, and all compilers wanting a working base class destructor (and it being a very bad programming practice for the base dtor not to be virtual).

To answer your second question, as soon as your ctor is non-empty, it isn't trivial. The closest you get to trivial is an empty ctor/dtor, and your careful reading of the standard already tells you that that's not defined to be trivial.

TL;DR: The standard defines a trivial dtor, but not an empty one. Smart compilers can choose to notice that it's user-defined empty and treat it as trivial, but the standard doesn't require any such consideration.

like image 128
Scott Mermelstein Avatar answered Oct 03 '22 18:10

Scott Mermelstein