Are undeclared copy-constructors automatically inline? - c++

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?

Related

Defaulted special member function with external definition

I would like to declare a class with a defaulted constructor1, but I want to this defaulted constructor to be "extern" in the sense the constructor body should only be compiled once, when the TU for the class is compiled, and not in each TU that includes that header. Finally, the class should should not be seen to have a user-provided constructor, but rather a defaulted one2.
For example, here's one attempt:
foo.hpp:
class Foo {
public:
Foo();
};
foo.cpp:
Foo::Foo() = default;
This results in a defaulted constructor implementation, but it means that Foo has a user-provded constructor, which affects the traits of the type, e.g., whether it is trivial, etc.
Here's another way:
foo.hpp:
class Foo {
public:
Foo() = default;
};
This preserves the "not user-provided" property, but now every TU that includes this class and uses the constructor will generate machine code for it (and this code might get inlined, etc).
1 Really, this applies to any special member functions, but I'm using the default constructor here for concreteness.
2 Whether the class has a user-provided constructor affects various important traits and behaviors of the class, such as whether it has a trivial constructor, whether other special member functions are implicitly deleted or not, etc.
There’s no way in the language to tell the compiler that a function is non-user-provided (“you know everything about it”) while also claiming that it’s opaque (“you can’t do the code generation here”). Fortunately, the obvious implementation strategy for C++20 modules has that effect: a member function defaulted in its class in a module interface unit will be considered for inlining everywhere but obviously needs only one out-of-line copy in the object file generated for the module.
If you want a stronger guarantee than that, you’re well into implementation-specific territory and you should look into compiler-specific attributes to govern code generation.

Are copy constructors defined implicitly always, or only when they are used?

Consider the following code:
#include <memory>
#include <vector>
class A
{
private:
std::vector<std::unique_ptr<int>> _vals;
};
int main()
{
A a;
//A a2(a);
return 0;
}
Compiler A compiles this without issue unless I uncomment out the line A a2(a); at which point it complains about the copy constructor for std::unique_ptr being deleted, and therefore I can't copy construct A. Compiler B, however, makes that complaint even if I leave that line commented out. That is, compiler A only generates an implicitly defined copy constructor when I actually try to use it, whereas compiler B does so unconditionally. Which one is correct? Note that if I were to have used std::unique_ptr<int> _vals; instead of std::vector<std::unique_ptr<int>> _vals; both compilers correctly implicitly delete both copy constructor and assignment operator (std::unique_ptr has a explicitly deleted copy constructor, while std::vector does not).
(Note: Getting the code to compile in compiler B is easy enough - just explicitly delete the copy constructor and assignment operator, and it works correctly. That isn't the point of the question; it is to understand the correct behavior.)
From [class.copy.ctor]/12:
A copy/move constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used ([basic.def.odr]), when it is needed for constant evaluation ([expr.const]), or when it is explicitly defaulted after its first declaration.
A's copy constructor is defaulted, so it's implicitly defined only when it is odr-used. A a2(a); is just such an odr-use - so it's that statement that would trigger its definition, that would make the program ill-formed. Until the copy constructor is odr-used, it should not be defined.
Compiler B is wrong to reject the program.
Note: My answer is based on your comment:
[...] it's only on Windows, and only when I explicitly list class A as a DLL export (via, e.g., class __declspec(dllexport) A) that this happens. [...]
On MSDN we can learn that declaring a class dllexport makes all members exported and required a definition for all of them. I suspect the compiler generates the definitions for all non-deleted functions in order to comply with this rule.
As you can read here, std::is_copy_constructible<std::vector<std::unique_ptr<int>>>::value is actually true and I would expect the supposed mechanism (that defines the copy constructor in your case for export purposes) checks the value of this trait (or uses a similar mechanism) instead of actually checking whether it would compile. That would explain why the bahviour is correct when you use unique_ptr<T> instead of vector<unique_ptr<T>>.
The issue is thus, that std::vector actually defines the copy constructor even when it wouldn't compile.
Imho, a is_copy_constructible check is sufficient because at the point where your dllexport happens you cannot know whether the implicit function will be odr-used at the place where you use dllimport (possibly even another project). Thus, I wouldn't think of it as a bug in compiler B.
While I can't confirm this behavior (I do not have access to Windows compiler, and OP claims the bug happens with icc on Windows platform), taking the question at it's face value, the answer is - compiler B has a gross bug.
In particular, implicitly-declared copy constructor is defined as deleted, when ...
T has non-static data members that cannot be copied (have deleted,
inaccessible, or ambiguous copy constructors);
https://en.cppreference.com/w/cpp/language/copy_constructor
Thus, conforming compiler must semantically generate deleted copy-constructor, and successfully compile the program since such constructor never called.

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.

Static data member with initializer

Assuming one is never odr-used, is there a benefit of declaring a static const or static constexpr data member with an initializer over declaring and then defining one later? Is there a benefit to not needing a definition?
First, note that you can't define a static const data member where you declare it. The declaration doesn't become a definition no matter what you do (such as providing an initializer). However, a static constexpr data member doesn’t need a definition, and the static const data member of integral type with initializer doesn’t need a definition if it’s never ODR-used.
ODR: the One Definition Rule, in the C++11 standard §3.2 [basic.def.odr].
Providing a definition is non-trivial in a header file – for a non-template class the direct approach would lead fast to violations of the ODR, with the linker complaining. Thus a benefit of not defining is that it makes it easy to use header-only modules. And a benefit of defining is that it makes it easy to use any type whatsoever, and supports ODR-use.
There are already a host of SO questions dealing with practical solutions to the requirement of definition for ODR use, with respect to header-only modules.
The ODR has a special exemption for templates for this, and that’s the basis of one practical solution. Just provide the definition in a class template, and use a dummy argument to instantiate the template. Another practical solution is to place the definition in a function, essentially a Meyers’ singleton.

Are the default constructor and destructor ever inline?

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.