Why would the implicitly generated constructor (et al.) be more efficient than a user-defined (trivial) one?
Asked Answered
P

4

11

I read this article from D. Kalev this morning about the new c++11 feature "defaulted and deleted functions", and can't understand the part about performance, namely:

the manual definition of a special member function (even if it's trivial) is usually less efficient than an implicitly-defined one.

By googling to find an answer, I found another article of the same author:

the synthesized constructor and copy constructor enable the implementation to create code that's more efficient than user-written code, because it can apply optimizations that aren't always possible otherwise.

There is no explication, but I read time to time similar claims.

But how is it that writing:

class C { C() = default; };

can be more efficient than

class C { C(){} };

? I though a compiler would be smart enough to detect such situation and optimize that. In other words how is it easier for the compiler to optimize when it sees =default instead of {} (void body function)?

Edit: the question was edited to add the "c++11" tag, but this question remains in c++03 context: just replace class C {C()=default;}; by class C {};, so not really a c++11 specific question.

Pepita answered 25/11, 2010 at 10:8 Comment(4)
Good question. I would also think that any compiler not optimizing this is defective. Let’s see if someone can give a good reason why that’s not possible.Linguistics
Try with a C++1x compiler to generate the assembly. This will answer your question definitely. I doubt there is any difference, since as you say, the compiler is smart enough. Comments like the one you quoted are bad, in my opinion, because it makes C++ developers to think too much about performance. 99% of the time there are other qualities to worry about before even considering silly micro performance-optimizations.Scrivings
@Daniel: thanks, but I know nothing about assembly, and I'm not at all interested in gaining micro-performance... But I'm interested to know why there would be any gain, be it micro.Pepita
are you sure they are similar, meaning, the second one is an inline definition but I am unsure about the first.Agler
D
7

You ask, how is it that

class C { C() = default; };

can be more efficient than

class C { C(){} };

Well, both constructors do nothing, so it's meaningless to talk about efficiency for that example.

But more generally, in e.g. a copy constructor one can imagine that copying one POD item at a time will not be recognized as optimizable by simple optimizer, whereas with automatic generation it might just do a memcpy. Who knows. It's a Quality of Implementation issue, and I can easily imagine also the opposite.

So, measure, if it matters.

Cheers & hth.,

Diaphoresis answered 25/11, 2010 at 10:20 Comment(3)
I totally agree, but Kalev gives almost the same example (a virtual default destructor in fact), and he says (quoted in the post): "even if it is trivial", hence my question. But I will never measure that, I wanted to understand the true reasons, not given by the author.Pepita
It's not true that both cases do nothing, they both initialize all the class's members using their default constructors (if they are not primitives)Forejudge
@Motti: in the concrete example above, they do nothing. In that case it's meaningless to talk about efficiency. In a modified example, one with data members, they will generally have different effect. And so in that case, although efficiency can be talked about, it's not comparable. I didn't see any point in discussing that hypothetical case. Cheers & hth.,Diaphoresis
G
7

It makes no sense whatsoever to talk about "manual definition of a special member function (even if it's trivial)", because user-provided special member functions are, by definition, non-trivial. This non-triviality comes into play when using type traits, and also POD-ness, and many optimizations are only possible with trivial or POD types.

A better restatement of the same quote would be:

The defaulted special member functions enable libraries to detect that calls to these functions may be omitted entirely.

From section 12.1 [class.ctor]

A default constructor is trivial if it is neither user-provided nor deleted and if:

  • its class has no virtual functions (10.3) and no virtual base classes (10.1), and
  • no non-static data member of its class has a brace-or-equal-initializer, and
  • all the direct base classes of its class have trivial default constructors, and
  • for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.

Otherwise, the default constructor is non-trivial.

From section 12.8 [class.copy]:

A copy/move constructor for class X is trivial if it is neither user-provided nor deleted and if

  • class X has no virtual functions (10.3) and no virtual base classes (10.1), and
  • the constructor selected to copy/move each direct base class subobject is trivial, and
  • for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;

otherwise the copy/move constructor is non-trivial.

From section 9, [class]:

A trivially copyable class is a class that:

  • has no non-trivial copy constructors (12.8),
  • has no non-trivial move constructors (12.8),
  • has no non-trivial copy assignment operators (13.5.3, 12.8),
  • has no non-trivial move assignment operators (13.5.3, 12.8), and
  • has a trivial destructor (12.4).

A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable. [ Note: in particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes. — end note ]

Gynecologist answered 11/12, 2010 at 17:15 Comment(0)
S
2

Take performance claims "with a grain of salt".

I've heard a high-rated MIT professor make a claim like that for his favorite thing, and the only reason nobody asked him "why" was because he was a high-rated MIT professor.

Such constructors and destructors might have other advantages, but claims about performance (outside of big-O) are seldom even meaningful except in highly contrived circumstances.

Sublet answered 25/11, 2010 at 15:44 Comment(0)
M
0

To be honest, I can't see it either.

Among other things, I can see why one should use

class C { C() = default; };

that seems to me the same as

class C { };

Or, if other constructors are provided, as:

class C { 
    C() {}
    // other constructors.
};

I fail to see the real problem the author is writing about here.

Mchale answered 25/11, 2010 at 10:19 Comment(4)
I do like Daniel Lidström's comment under the question here. I think it points at what unreal problem the author is writing about.Stein
The first two ARE the same, the default constructor is defaulted, explicitly or implicitly makes no difference. "If other constructors are provided" is exactly the reasoning for the new = default syntax, since it allows creating a trivially-copyable class with user-defined conversions. The constructor with an empty body is sufficient to make the class non-trivially copyable.Gynecologist
@Ben ok, but it seems to me that the point of the article was the ability, by the compiler, to output a more optimized binary with the = default syntax.Mchale
I suggest you read my answer for a more detailed look. There's a problem with the article insofar as the author isn't using the standard definition of trivial (and I don't mean commonly accepted definition, I mean the ISO C++ standard explicitly states what trivial means in the context of C++ classes, constructors, and destructors). And the result is that the difference between a defaulted constructor and an empty user-defined one is not important to the compiler, but to library code that uses type traits. For some libraries it could be a very big difference indeed.Gynecologist

© 2022 - 2024 — McMap. All rights reserved.