Are the default constructor and destructor ever inline? - c++

I'm curious if the default constructor and destructor that the compiler generates are inline or not, because I can justify it either way. On the one hand, you want the default constructor/destructor to not be inline so that adding them later doesn't break ABI (because object files compiled when only the defaults were there will have inlined the generated definitions instead of what you define). On the other hand, for a C++ compiler to compile C code that performs as well as when compiled with a C compiler, it can't be adding constructor/destructor calls for every allocated struct, and in C++ the only functional difference between a class and a struct is supposed to be the default access protection. Maybe the linker addresses this somehow? Maybe the answer varies across compilers?
A consequence of this question: if I have a POD struct in C++, can I theoretically benefit under some compilers by defining empty inline constructor/destructors myself in place of the defaults?

The C++ standard says, in 12.1[class.ctor]/5
An implicitly-declared default constructor is an inline public member of its class
and in 12.4[class.dtor]/3
An implicitly-declared
destructor is an inline public member of its class.

if I have a POD struct in C++, can I theoretically benefit under some compilers by defining empty inline constructor/destructors myself in place of the defaults?
Theorotically, Yes! Any function(including constructors & destructors) can be declared inline, and putting the function body in the class definition is one way of doing that. However, it's up to the compiler if it actually does inline the function.

It varies across compilers, but in general: yes, they should.
With gcc at least, you get both an inline and an out-of-line function generated. The out-of-line version is marked as "link once", so no matter how many objects generate a default constructor, at most only one version will end up in the linked output. If in fact nobody uses the default constructor out-of-line, it's not included in the linked output at all, and you have effectively a purely inline function.

Related

How can I force generation of a non-inlined *copy* of an inlined constructor in some unit?

In a DLL (built with MSVC) I have a legacy published class in a C++ header, that declares a non-illine constructor (and non-inline, virtual destructor), defined in a unit. That means that library users expect the constructor implementation in the library.
Due to performance reasons, I would like the constrictor to be inlined for the internal code. However, just defining it inline in the header would mean that users might not find the non-inlined definition in the library. At least that is my understanding - which might be wrong; is it guaranteed by something (in MSVC, or in the standard) that the implementation is emitted for such class?
So the question is: if it's possible to guarantee emitting the implementation of inlined constructor in the DLL in some way, so that inlining would work for the newly compiled code, but existing binaries will still keep finding non-inlined implementation. Since I can't take the address of the constructor, I can't use this trick.
Another way would be to create another constructor, with a dummy argument, to be used in internal code, and leave the old default constructor alone; but if possible, I'd like to avoid increasing the complexity here.

Why are the default constructor and destructor of a class inline?

I read from multiple sources that:
If no user-declared constructors of any kind are provided for a class type (struct, class, or union), the compiler will always declare a default constructor as an inline public member of its class.
Why was this decision made (to explicitly declare ctors/dtors as inline)? Compilers are free to inline / non-inline this anyways? Especially since inlining ctors may have a huge penalty on the clients of a class (Effective C++, Item #30)?
They're not inline in the sense "they will always be inlined by the compiler." They are inline in the sense "considered defined in every translation unit which sees the class definition, without violating the One Definition Rule (ODR)." Note that the latter is the only meaning of the phrase "inline function" which standard C++ uses.
Explicitly marking a function with the inline keyword is also a non-binding hint to the compiler to actually inline the function, but I doubt modern compilers & optimisers pay much attention to this hint. However, note that this (hint to inline) applies only to using the keyword inline, and not to functions implicitly inline (such as the defaulted constructor and destructor mentioned in the question).
inline has two meanings in the C++ standard.
The first is what you think of when you hear inline; taking the code in the function and injecting it into the place where it is called.
The C++ standard advises implementations to do this when they see an inline method or function, but does not require it. As such action has zero observable behavior changes in the abstract machine that the C++ standard describes, I consider it non-normative advice.
The second has to do with linking. An inline function (or in C++17 a variable) can exist in multiple translation units. Normally this causes an error at link-time; but when the variable or function is inline, instead all but one of the instances of the variable or function are silently discarded. If they differ in any important way, this makes your program ill-formed no diagnostic required.
This second meaning is why implicit ctors and dtors are implicitly inline; it means that no single translation unit has to be chosen for them to "live in". Instead, they are generated everywhere they are needed. They may be preferentially actually inlined into calling code, but most importantly if any vestigial copies of it still exist (because it was not inlined, say), no error occurs at link time, and instead all but one of them are discarded.
See inline in the C++ standard. The wording in the standard is a bit harder to understand, different and more precise than I use above.

Are undeclared copy-constructors automatically inline?

Are undeclared (auto-generated) copy constructors automatically marked as inline?
If so, and if I don't want them to be marked as inline, does that mean I have to define one manually and copy every single member I need by hand (assuming I'm not using C++11, so that there's no = default to take advantage of)?
They're treated as if they were declared inline (which doesn't
necessarily mean that they will be inlined). And yes, in
pre-C++11, the only way to prevent their being inline was to
declare and define them manually, copying every member and every
base class explicitly in the initializer list.
Yes. From C++11, 12.8/11:
An implicitly-declared copy/move constructor is an inline public member of its class.
I would strongly suggest reading all of 12.8 if you like to get more familiar with copy and move constructors.
They are, I believe. However, for a such a compiler-defined function, the difference between inline and not is non-observable. And yes, you would have to define your own for it to be non-inline, although why you would want such a thing is beyond me. It makes no difference to the semantics and won't affect the compiler's inlining.
Implicitly defined special member functions are inline and they must be as they can be implicitly generated in multiple translation units. The meaning of inline is that it can be defined in multiple translation units without violating the ODR, not that the code will actually be inlined (this depends on the type and the compiler).
Why don't you want the copy constructor to be inline?

What are the inlining rules within C++ classes?

From what I read somewhere long time ago, it seems that if you want class member function to be inlined during the compilation phase, the function has to be defined inside class declaration block.
But this has a downside of a detail leak. IMHO, other programmers should only see class interface when opening .h file.
Is the first statement still true in modern C++, was it ever? Is there a way to force inlining for functions that are declared, preferably in another file altogether?
Is it generally better to keep short member functions inside class declaration block, or not?
It seems that if you want class member function to be inlined during the compilation phase, the function has to be defined inside class declaration block.
That is not really true. A function that is defined inside the class definition is implicitly marked as inline. But you don't need to defined the function inside the class for it to be inline, you can explicitly request it:
struct X {
void f();
};
inline void f() {}
The inline keyword on the other hand, does not mean that the function will be inlined, but rather that it can be defined in multiple translation units, that is, if multiple translation units include the same header that contains that definition, the linker will not fail with a multiple definition error.
Now, on actual inlining, the compiler can decide to inline or not any function, regardless of whether the function is declared as inline provided that it sees the definition of that function (the code that it will inline), which is the reason why in general functions that are meant to be inlined should be defined in the header (either inside the class definition or marked inline outside.
Additionally, newer toolchains can perform whole program optimization or other link time optimizations, by which the linker can also decide that a function should be inlined. In this case, the function definition needs not be visible at the call site, so it could be defined inside the .cpp file. But if you really want the function to be inlined it is better not to depend on this feature and just define the function in the header.
Q: Is there a way to force inlining for functions?
A: No
No matter how you designate a function as inline, it is a request that
the compiler is allowed to ignore: it might inline-expand some, all,
or none of the calls to an inline function.
Q: What are the inlining rules within C++ classes?
Inline member functions in C++
As far as Standard C++ is concerned, a inline function must be defined
in every translation unit in which it is used
...
This is different from non-inline functions which must be defined only
once in an entire program (one-definition-rule)...
For member-functions, if you define your function in the class, it is
implicitly inline. And because it appears in the header, the rule that
it has to be defined in every translation unit in which it is used is
automatically satisfied.
Here is a great FAQ (one that's more "practical" than "pedantic"):
http://www.parashift.com/c++-faq-lite/inline-functions.html
Is the first statement still true in modern C++, was it ever?
As David explained, there's the inline keyword as well. It can be ignored, as Paul stated.
Is there a way to force inlining for functions that are declared,
preferably in another file altogether?
Probably by configuring your compiler. It might be doing some inling behind your back anyway. Eg. gcc has -finline-functions etc. that will be switched on for certain optimisation levels
Is it generally better to keep short member functions inside class declaration block, or no?
Up to you. Be aware though that if you have an inline method used lots of times, then you can be increasing the size of your object files, and so potentially bloat the size of what you're building and maybe slow it down.
FWIW I only tend to put implementations in header files out of laziness :)

Why are inline constructors and destructors not a good idea in C++?

I remember reading in one of the C++ books (quite some time ago) that it is not a good idea to have inline Constructors and Destructors especially for derived class.
I understand that inlining would induce some bloating up of object code but are there any other design considerations that discourage inline constructors and destructors? Of course most compilers may reject the inline and proceed with creating a function body but if they were to inline what penalty might one have to pay?
The compiler is free to inline code that you have not declared inline, and is free not to inline code that you have declared inline. I have seen compilers do both of these things. Because of this the inline keyword does not mean what most people think it does. It's meaning is to allow an exception to the one definition rule, so you can put functions etc. in a header file and not get linker errors.
So the advice is rubbish, let the compiler decide what is best to inline and what is not. Put inline where you need it to prevent linker errors, that is all.
There's absolutely no reason whatsoever to avoid inline constructors and destructors. The book is wrong as wrong can be.
I don't know about constructors, but destructors are very often virtual. In most cases, it doesn't make sense for the compiler to inline virtual functions, because it's not known until runtime which override is going to be called.
Apart from the reason #oli mentions in his answer:
The book probably guides on not inlining constructors and destructors, because even seemingly trivial or empty functions might often contain lot of implicitly generated code by the compiler and the actual function definition might end up being quite large, This might result in code bloat.
Having said so, It is prudent to let the compiler actually decide whether to inline or not inline a function call (even constructors and destructors), most of modern day compilers will appropriately optimize functions through in-lining.
I'm pretty sure this is not about what C++ does with the code, because, as said, it's just a hint.
If you start looking at software engineering consideration things change. All inline function changes will force recompilations of all dependent files.
It get worse when you maintain a library and want to send out a bug fix version, remaining ABI compatible. Inline functions can simply not be replaced by another version because the calling code may not be recompiled. So where your non-inline function can be replaced at will, you have to move to a new version of your interface when inline functions ned to be changed.
Combine this with the fact that constructors can seldom be actually inlined by the compiler, then you I can imagine why a book would give the advice mentioned.