A lot of attention has been received by = default and = delete with respect to the special members (default constructor, destructor, copy and move). Can = default and = delete be used with other functions; member functions, free functions and operators etc.?
I can understand that = default would probably not be allowed outside the special members; since it is basically saying use the compiler generated default. The default would need to be clearly defined before the compiler is able to generate it. As far as I know, only the special members have these pre-defined defaults.
What about = delete; it is basically saying that the function is declared, but the implementation is explicitly not defined.
Can = delete be used with functions other than the special members?
What function types can it be used on (members, non-members, operators etc.)?
Or conversely, where (or when) is = delete prohibited from being used? Are there any restrictions on its use?
Any function whatsoever can be declared as deleted (using = delete). The standard does not impose any restrictions. This is covered by C++11[dcl.fct.def.delete]. It even gives an example of a deleted operator new.
Defaulted functions, on the other hand, are limited by [dcl.fct.def.default]§1 as follows:
1 ... A function that is explicitly defaulted shall
be a special member function,
have the same declared function type (except for possibly differing ref-qualifiers and except that in the case of a copy constructor or copy assignment operator, the parameter type may be “reference to
non-const T”, where T is the name of the member function’s class)
as if it had been implicitly declared, and
not have default arguments.
The "special member functions" referenced in the first bullet point are (as per [special]§1):
default constructor
copy constructor
move constructor
copy assignment operator
move assignment operator
destructor
Related
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.
Does the presence of a user-defined "Rule of 5" function (destructor, copy constructor, copy-assignment operator, move constructor, or move assignment operator) in a particular class affect whether these functions will get generated in its derived or base classes? If so, in what way?
Put another way, if I'm trying to determine what functions will be implicitly generated for a particular class, do I need information about it's parent or child classes?
Optional Question: Does the presence of one of these functions in a particular class affect the generated code for implicitly generated functions of other classes in the hierarchy? If so, in what way?
The compiler will always declare a destructor for a class C that has no user-declared destructor (C++17 [class.dtor]/4). However, if any base class of C has a deleted or inaccessible constructor, then C's destructor will also be declared as deleted (p5).
A similar statement holds for copy constructors ([class.copy.ctor]/6) and copy assignment operators ([class.copy.assign]/2).
In the case of a move constructor, the compiler will only implicitly declare it for a class C if the user did not declare any Rule of 5 functions for C ([class.copy.ctor]/8). The base classes of C can affect whether the move constructor of C is deleted or not, but they do not affect whether the compiler generates a declaration. A similar statement holds for move assignment operators ([class.copy.assign]/4).
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 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.