I've been reading the C++ standard trying to understand if there are any observable differences between trivial, simple, and implicitly defined constructors/assignment operators/destructors. From my current understanding there doesn't seem to be a difference, but that seems odd, why spend so much time defining them when it doesn't matter?
As a particular concrete example, consider copy constructors.
A trivial copy constructor copies all fields and base classes field-by-field if all fields and base classes are trivial.
Otherwise, the implicitly generated copy constructor: "performs full member-wise copies of bases and non-static members in initialization order".
If I understand it correctly, if a class has all trivial bases and fields but has a defaulted copy-constructor, then the defaulted copy-constructor will do exactly the same thing as the trivial constructor. Not even the initialization order seems to be relevant here because the fields are all disjoint (since trivial implies the absence of virtual base classes).
Is there ever an instance when a trivial copy-constructor will do something different than an explicitly defaulted copy constructor?
Generally, the same logic seems to hold for other constructors and destructors as well. The argument for assignment is a little bit more complex due to the potential for data races, but it seems like all of those would be undefined behavior by the standard if the class was actually trivial.
Not exactly about the behavior of the actual special member function per-se*, but consider the following:
struct Normal
{
int a;
};
static_assert(std::is_trivially_move_constructible_v<Normal>);
static_assert(std::is_trivially_copy_constructible_v<Normal>);
static_assert(std::is_copy_constructible_v<Normal>);
This all seems well and good.
Now consider the following:
struct Strange
{
Strange() = default;
Strange(Strange&&) = default;
};
static_assert(std::is_trivially_move_constructible_v<Strange>);
static_assert(!std::is_trivially_copy_constructible_v<Strange>);
static_assert(!std::is_copy_constructible_v<Strange>);
Hmm. The mere act of explicitly defaulting a move constructor disallows the object from being copy constructible!
Why is this?
Because, even though the compiler is still defining the move constructor for Strange, it's still a user-declared move constructor, which disables the generation of the copying special member functions.
The standard is very finicky about which special member functions get generated when you have user-declared versions of them, so it's best to stick with the Rule of Five or Zero.
Live Demo
Extra credit
By explicitly defaulting a default constructor for Strange, it is no longer an aggregate type (whereas Normal is). This opens up a whole different can of worms about initialization.
*Because as far as I know, the behavior of an explicitly defaulted special member function is identical to the trivial version of that function (or rather, it's the other way around). However, I have to note one peculiarity about the standard wording; when discussing the implicitly declared copy constructor, the standard neglects to say "implicitly declared as defaulted" like it does for the default and move constructors. I believe this to be a minor typo.
As a particular concrete example, consider copy constructors.
A trivial copy constructor copies all fields and base classes field-by-field if all fields and base classes are trivial.
Otherwise, the implicitly generated copy constructor: "performs full member-wise copies of bases and non-static members in initialization order".
The Standard specifies the behavior of implicitly defined special functions in just one place each. For example, [class.copy.ctor]/11 defines whether or not a copy or move constructor qualifies as "trivial". [class.copy.ctor]/14, which contains the quote about "performs a memberwise copy/move", applies whether or not the copy or move constructor is "trivial". When paragraph 11 talks about "the constructor selected" to move a base or member, it's referring to the choices made by the (potential) definition described by paragraph 14.
So yes, being trivial doesn't make a difference for how the class object is initialized. Instead, it makes a difference for other uses of an object of that type, sometimes to allow treating the class type in a more "C-like" way. This isn't a complete listing, but some notable Standard rules which reference triviality:
Implicitly declared special member functions of a union or class containing an anonymous union are defined as deleted if the corresponding special member of any class-type variant member is not trivial.
It's valid to copy objects of a trivially copyable class (see [class.prop]/1) byte by byte. ([basic.types]/2-3).
It's always valid to pass an object of class type through a C-style variadic function's ... if the copy constructor, the move constructor (if any), and the destructor are all trivial. Otherwise, passing an object of the class type is conditionally supported. ([expr.call]/12)
Of course, the std::is_trivially_* traits can tell the difference.
Related
When a class explicitly declares a copy operation (i.e., a copy constructor or copy assignment operator), move operations are not declared for the class. But when a class explicitly declares a move operation, the copy operations are declared as deleted. Why does this asymmetry exist? Why not just specify that if a move operation is declared, no copy operations will be declared? From what I can tell, there would not be any behavioral difference, and there would be no need for the asymmetric treatment of move and copy operations.
[For people who like citations of the standard, the lack of declaration of move operations for classes with copy operation declarations is specified in 12.8/9 and 12.8/20, and the deleted copy operations for classes with move operation declarations are specified in 12.8/7 and 12.8/18.]
When a class would be moved but for the fact that no move constructor is declared, the compiler falls back to copy constructor. In the same situation, if move constructor is declared as deleted, the program would be ill-formed. Thus, if move constructor were implicitly declared as deleted, a lot of reasonable code involving existing pre-C++11 classes would fail to compile. Things like myVector.push_back(MyClass())
This explains why move constructor cannot be implicitly declared deleted when copy constructor is defined. This leaves the question of why copy constructor is implicitly declared deleted when move constructor is defined.
I don't know the exact motivation of the committee, but I have a guess. If adding a move constructor to existing C++03-style class were to remove a (previously implicitly defined) copy constructor, then existing code using this class may change meaning in subtle ways, due to overload resolution picking unexpected overloads that used to be rejected as worse matches.
Consider:
struct C {
C(int) {}
operator int() { return 42; }
};
C a(1);
C b(a); // (1)
This is a legacy C++03 class. (1) invokes an (implicitly defined) copy constructor. C b((int)a); is also viable, but is a worse match.
Imagine that, for whatever reason, I decide to add an explicit move constructor to this class. If the presence of move constructor were to suppress the implicit declaration of copy constructor, then a seemingly unrelated piece of code at (1) would still compile, but silently change its meaning: it would now invoke operator int() and C(int). That would be bad.
On the other hand, if copy constructor is implicitly declared as deleted, then (1) would fail to compile, alerting me to the problem. I would examine the situation and decide whether I still want a default copy constructor; if so, I would add C(const C&)=default;
Why does this asymmetry exist?
Backward compatibility, and because the relationship between copying and moving is already asymmetrical. The definition of MoveConstructible is a special case of CopyConstructible, meaning that all CopyConstructible types are also MoveConstructible types. That's true because a copy constructor taking a reference-to-const will handle rvalues as well as lvalues.
A copyable type can be initialized from rvalues without a move constructor (it just might not be as efficient as it could be with a move constructor).
A copy constructor can also used to perform a "move" in implicitly-defined move constructors of derived classes when moving the base sub-object.
So a copy constructor can be seen as a "degenerate move constructor", so if a type has a copy constructor it doesn't strictly need a move constructor, it is already MoveConstructible, so simply not declaring the move constructor is acceptable.
The opposite is not true, a movable type is not necessarily copyable, e.g. move-only types. In those cases, making the copy constructor and assignment deleted provides better diagnostics than just not declaring them and getting errors about binding lvalues to rvalue references.
Why not just specify that if a move operation is declared, no copy operations will be declared?
Better diagnostics and more explicit semantics. "Defined as deleted" is the C++11 way to clearly say "this operation is not allowed", rather than just happening to be omitted by mistake or missing for some other reason.
The special case of "not declared" for move constructors and move assignment operators is unusual and is special because of the asymmetry described above, but special cases are usually best kept for a few narrow cases (it's worth noting here that "not declared" can also apply to the default constructor).
Also worth noting is that one of the paragraphs you refer to, [class.copy] p7, says (emphasis mine):
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
"The latter case" refers to the "otherwise, it is defined as defaulted" part. Paragraph 18 has similar wording for the copy assignment operator.
So the intention of the committee is that in some future version of C++ other types of special member function will also cause the copy constructor and copy assignment operator to be deleted. The reasoning is that if your class needs a user-defined destructor then the implicitly-defined copy behaviour is probably not going to do the right thing. That change hasn't been made for C++11 or C++14 for backward compatibility reasons, but the idea is that in some future version to prevent the copy constructor and copy assignment operator being deleted you will need to declare them explicitly and define them as defaulted.
So deleting copy constructors if they might not do the right thing is the general case, and "not declared" is a special case just for move constructors, because the copy constructor can provide the degenerate move anyway.
It is essentially to avoid migrated code to perform unexpected different actions.
Copy and move require a certain level of coherence, so C++11 -if you declare just one- suppress the other.
Consider this:
C a(1); //init
C b(a); //copy
C c(C(1)); //copy from temporary (03) or move(11).
Suppose you write this in C++03.
Suppose I compile it later in C++11.
If no ctor are declared, the default move does a copy (so the final behavior is the same as C++03).
If copy is declared, move is deleted, and sine C&& decays into C const& The third statement result in a copy from a temporary. This is still a C++03 identical behavior.
Now, if I'm adding later a move ctor, it means I'm changing the behavior of C (something you did not plan when defining C in C++03), and since a movable object does not need to be copyable (and vice versa), The compiler assumes that by making it movable, the dafault copy may be not anymore adequate. It's up to me to implementing it in coherence with the move or -if I found it adequate- restore the C(const C&)=default;
As I knew until today there are four default things create when creating a new class. "Default constructor", "Destructor", "Copy constructor" and "Assignment operator". But today when I was going trough a C++ article, it said that there can be situations where the copy constructor is not create by default.
Is that true?
If it is, in which situations?
In those situations, how can an instance of that class be passed by value?
1) Yes, there can be situations where the copy constructor is not created by default.
2) The conditions where the implicitly declared default constructor is deleted are laid out in 12.8 Copying and moving class objects [class.copy]:
12.8.7 is about how the declaration of other special member functions affect the implicitly declared copy constructor. Whenever the class declares a copy constructor, a move constructor or a move assignment operator. If it declares any one of those, then you don't get an implicitly declared one.
...
7 If the class definition does not explicitly declare a copy
constructor, one is declared implicitly. If the class definition
declares a move constructor or move assignment operator, the
implicitly declared copy constructor is defined as deleted; otherwise,
it is defined as defaulted (8.4). The latter case is deprecated if the
class has a user-declared copy assignment operator or a user-declared
destructor.
12.8.11 is about how the data members and base classes affect the implicitly declared copy constructor. Essentially, if the class has any data members or base classes that are not copyable, the implicitly declared copy constructor is deleted:
11 An implicitly-declared copy/move constructor is an inline public
member of its class. A defaulted copy/ move constructor for a class X
is defined as deleted (8.4.3) if X has:
— a variant member with a
non-trivial corresponding constructor and X is a union-like class,
— a non-static data member of class type M (or array thereof) that cannot
be copied/moved because overload resolution (13.3), as applied to M’s
corresponding constructor, results in an ambiguity or a function that
is deleted or inaccessible from the defaulted constructor,
— a direct or virtual base class B that cannot be copied/moved because overload
resolution (13.3), as applied to B’s corresponding constructor,
results in an ambiguity or a function that is deleted or inaccessible
from the defaulted constructor,
— any direct or virtual base class or
non-static data member of a type with a destructor that is deleted or
inaccessible from the defaulted constructor,
— for the copy
constructor, a non-static data member of rvalue reference type, or
...
3) You can declare and define (either by providing an implementation or defaulting a copy constructor, or a move copy constructor, or both.
Yes, that is correct. For example, if a member of the class is not copyable/assignable (e.g. a member has a private assignment operator and private copy constructor), then you won't be able to rely on a default copy constructor for the containing class. If you want the containing class to be copyable/assignable under those circumstances, then you need to define those operations explicitly.
That being said, in most cases, you should avoid passing by value. In most circumstances, you should be passing an object by constant reference or passing a smart pointer (e.g. std::unique_ptr) of your object. Passing by value (and any code that does an unnecessary amount of copying) will produce less efficient code than cases where you are able to reuse existing implementations. Additionally, for polymorphic objects, pass-by-value causes "slicing" (the functionality is truncated from the runtime type to the declared type to which the object is being copied), and so pass-by-value is particularly dangerous and error-prone when operating with any data types that might possibly be inherited.
Edit
To clarify the above a little bit... in terms of passing by const-reference vs passing by value, the decision should depend on the size of the object and how expensive it is to copy. Boost provides a handy mechanism in "call traits" (call_traits<T>::param_type) to automatically select between a value and a const reference based on the size of an object. When making this decision, it's also useful to distinguish between value types (objects that behave similarly to primitives -- for example, by overloading various operators and that are copyable, assignable, and cannot be inherited) and user-defined polymorphic types. Whenever you have a type that declares a virtual method, as a general rule of thumb, that object should be passed by reference or const reference to avoid the slicing which I mentioned above.
In terms of passing by smart pointer, generally this is done when transferring or sharing ownership (otherwise you should generally just pass around a reference to the object in question).
I actually got the idea of this question when I was discussing on another question of mine (Member not zeroed, a clang++ bug?). That question is about C++11 value-initialization, but when I saw the C++03 value-initialization rule someone posted there, I am confused.
The value-initialization rule from C++03 is:
To value-initialize an object of type T means:
if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default
constructor);
if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is
value-initialized;
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized
Please look at the second bullet which defines the value-initialize process for a type without user-declared constructor. This rule doesn't mention a constructor call. As we can see from the description of other cases of value-initialize or from the description of default-initialize, if constructor should be called, it will be explicitly mentioned in the text of the standard. I know there is certain initialization form that constructor doesn't get called (e.g. {}-initialization for aggregates), but should it be the case for value-initialize of non-union class type without a user-declared constructor? The implicitly declared constructor of such a type could easily be non-trivial. For example:
class A {
public:
virtual void f() {}
};
According to the rule in C++03, if the implicitly declared non-trivial constructor doesn't get called in the process of the value-initialization of an object of A, how does the vptr of the object get setup? (I know things related to vptr is all implementation-defined, but this doesn't change the major point I'm trying to make here.)
(Someone would argue that the absence of mentioning a constructor call in the rule doesn't mean constructor won't get called. OK. Let's say constructor will get called according to some other rule I may have overlooked, but since all members need to be value-initialized anyway, wouldn't that cause the members' constructors to be called more than once?)
Asking a question for C++03 when it's already C++11 everywhere may seem worthless. Yeah, that's a valid point. However, I think I could more or less learn something if I finally figure this out (whether I am wrong and why).
EDIT: Maybe I shouldn't have used vptr as an example. My point is, wouldn't skipping the call to a non-trivial constructor cause some potential problem for the validity of the object? After all, it's called non-trivial for a reason.
As far as the Standard is concerned, the constructor is not responsible for setting up the vtable. There is nothing responsible for setting up the vtable; vtables don't exist, as far as the Standard is concerned.
Rather, the vtable is a consequence of the other rules the compiler has to follow, relating to virtual function binding and such. So whether or not the constructor is called, the vtable's going to be set up somewhere, because otherwise the compiler will have trouble meeting its other obligations. That doesn't contradict the value-initialization rule; rather, it adds nuance to the practicalities of implementing the rule.
When a class X has no user-provided constructor, its default constructor does exactly what a constructor of the form X::X() {} would (C++03[class.ctor]§6). And as far as the standard is concerned, this is defined to perform default initialisation of all members and base class subobjects, and nothing else. So "calling the generated default constructor" is identical to "default-initialising all data members and base class subobjects."
So this actually does "less" than the value initialisation you quoted - as that value initialisation value-initialises all data members and base class subobjects. So it does all the constructor does, and more.
As far as implementation-specific things (like the vtable pointer) go, these are outside of the scope of the standard. It is a compiler's responsibility to make sure all of its implementation-specific mechanisms work regardless of constructor calls mandated by the standard.
This is where I got most of this information: http://en.cppreference.com/w/cpp/language/move_constructor
Apparently these are the conditions for the implicitly generated move constructor to work:
there are no user-declared copy constructors
there are no user-declared copy assignment operators
there are no user-declared move assignment operators
there are no user-declared destructors
the implicitly-declared move constructor is not defined as deleted
if a user declared move constructor is present, it is still possible to still force the generation of the implicitly declared move constructor with the keyword default
My questions are:
Is it safe to rely on implicit automatic move constructor?
How do I check if it really worked instead of default copy constructor?
Finally, and most importantly, is it a good idea and why? Or is it always better to define my own?
I am more inclined to follow the rule of three and manually create a destructor, a copy and move constructor, and a copy and move assignment operator, but I'm just curious about this implicit one.
Here are the answers to your questions:
What do you mean with "safe"? When the rules apply, i.e., the subobjects are movable and you didn't do anything to stomp on the generation of the move constructor, it will be created and used when present. Note, however, that it is easy to have a non-movable subobject which will somewhat invisibly inhibit the creation of a move constructor.
To see if your class got a move constructor, just temporarily add an empty base logging when the copy and the move constructors are used and force the object to be moved/copied: it will log the correspondingly used constructor.
No code is generally better than any code.
1. Is it safe to rely on implicit automatic move constructor?
Nothing is safe to rely upon without testing (implicit or explicit).
2. How do I check if it really worked instead of default copy constructor?
Testing. See the example test below.
3. Finally, and most importantly, is it a good idea and why? Or is it
always better to define my own?
There are distinct (and growing) advantages to making your special members trivial. A trivial special member is one defined/supplied by the compiler. You can declare a trivial member with = default. Actually that last sentence is an exaggeration. If you declare a special member with = default, it won't for sure be trivial. That depends on your members and bases. But if you define a special member explicitly (as in C++98/03), then for sure it will not be trivial. If you have a choice between user-provided and trivial, prefer trivial.
Furthermore, you don't need to test if your type X has a move constructor. You need to test that if you move construct your X, that it has the right exception safety, and the right performance. If X::X(const X&) accomplishes that task, then so be it. In that case X::X(X&&) is not necessary.
If you expect that your type X will have a throwing copy constructor, and a much faster noexcept move constructor, here is a really nice test to confirm it is so:
static_assert(std::is_nothrow_move_constructible<X>::value,
"X should move construct without an exception");
Put this test right in your source/header. Now, no matter whether you implicitly, or explicitly declare or define your special members, you've got a concrete compile-time test that is practically zero cost. The static_assert generates zero code, and consumes a negligible amount of compile time.
I was reading this http://en.wikipedia.org/wiki/C%2B%2B0x#Modification_to_the_definition_of_plain_old_data
It mentions trivial default constructor, trivial copy constructor, copy assignment operator, trivial destructor. What is trivial and not trivial?
In simple words a "trivial" special member function literally means a member function that does its job in a very straightforward manner. The "straightforward manner" means different thing for different kinds of special member functions.
For a default constructor and destructor being "trivial" means literally "do nothing at all". For copy-constructor and copy-assignment operator, being "trivial" means literally "be equivalent to simple raw memory copying" (like copy with memcpy).
If you define a constructor yourself, it is considered non-trivial, even if it doesn't do anything, so a trivial constructor must be implicitly defined by the compiler.
In order for a special member function to satisfy the above requirements, the class must have a very simplistic structure, it must not require any hidden initializations when an object is being created or destroyed, or any hidden additional internal manipulations when it is being copied.
For example, if class has virtual functions, it will require some extra hidden initializations when objects of this class are being created (initialize virtual method table and such), so the constructor for this class will not qualify as trivial.
For another example, if a class has virtual base classes, then each object of this class might contain hidden pointers that point to other parts of the very same object. Such a self-referential object cannot be copied by a simple raw memory copy routine (like memcpy). Extra manipulations will be necessary to properly re-initialize the hidden pointers in the copy. For this reason the copy constructor and copy-assignment operator for this class will not qualify as trivial.
For obvious reasons, this requirement is recursive: all subobjects of the class (bases and non-static members) must also have trivial constructors.
A constructor of a class A is trivial if all the following are true:
It is implicitly defined (compiler synthesized)
A has no virtual functions and no virtual base classes
All the direct base classes of A have trivial constructors
The classes of all the nonstatic data members of A have trivial constructors
There are correct answers already, but here is the quote from the Standard (which I was looking for when I came across this post):
(§12.1/5)
A default constructor is trivial if it is not user-provided 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.
This is from C++11. C++03 lacks the second item and uses the phrase implicitly declared instead of not user-provided. It is otherwise identical.
Note that this specification only covers trivial default constructors. The word attribute trivial can also be used in different contexts, e.g. copy constructors.