In C++11, if the base class has defined its own move (copy) constructor (assignment operator), does its subclass need to define its own move (copy) constructor (assignment operator) in where call the base class's corresponding constructor/operator is called explicitly?
Is it a good idea to define the constructor, destructor, move/copy constructor (assignment operator) clearly every time?
struct Base {
Base() {}
Base(Base&& o);
};
struct Sub : public Base {
Sub(Sub&& o) ; // Need I do it explicitly ? If not,what the compiler will do for me
};
The compiler will generate a default move constructor if you don't specify one in the base class (except some cases, e.g. there's a base class with a deleted move constructor) but you should, in any case, call explicitly the base class' one if you have it:
Sub(Sub&& o) : Base(std::move(o))
According to the standard (N3797) 12.8/9 Copying and moving class objects [class.copy]:
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
— X does not have a user-declared copy constructor,
— X does not have a user-declared copy assignment operator,
— X does not have a user-declared move assignment operator, and
— X does not have a user-declared destructor.
As such, if your class meets the above requirements then a default move constructor will be implicitly declared for you.
As already being stated, the base-class has no knowledge of any sub-classes. As such, whether you declare a move constructor in one base class has no effect on the implicit generation of a move constructor in its sub-classes.
As far as it concerns whether you should declare explicitly a constructor/destructor etc. of a class, there's this nice article.
No, you don't have. I'll be automatically generated like default/copy constructor.
From this page,
Implicitly-declared move constructor
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
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
(until C++14) the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section
then the compiler will declare a move constructor as an inline public member of its class with the signature T::T(T&&).
A class can have multiple move constructors, e.g. both T::T(const T&&) and T::T(T&&). If some user-defined move constructors are present, the user may still force the generation of the implicitly declared move constructor with the keyword default.
Your struct Sub has no user-declared copy constructors, copy assignment operators, move assignment operators or destructors.
And,
Trivial move constructor
The move constructor for class T is trivial if all of the following is true:
It is not user-provided (meaning, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined
T has no virtual member functions
T has no virtual base classes
The move constructor selected for every direct base of T is trivial
The move constructor selected for every non-static class type (or array of class type) member of T is trivial
T has no non-static data members of volatile-qualified type
(since C++14)
A trivial move constructor is a constructor that performs the same action as the trivial copy constructor, that is, makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially movable.
Implicitly-defined move constructor
If the implicitly-declared move constructor is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler. For union types, the implicitly-defined move constructor copies the object representation (as by std::memmove). For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.
The move constructor of Base is not trivial (it's user-defined). So, the implicitly-defined move constructor of Sub will work as "the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument."
Related
I'm running a static analysis tool and getting an error because an abstract class, with no data members, has no constructors.
Given an abstract class with no data members:
class My_Interface
{
public:
virtual void interface_function(void) = 0;
};
Are any constructors generated by the compiler?
If a constructor is generated, what would it's content be?
If a constructor is generated, would it be eliminated by an
optimization level?
The rule documentation in the static analysis says:
If you do not write at least one constructor in a class, the compiler will
write a public constructor for you by default. This rule detects if you
do not declare at least one constructor.
The rule documentation references Scott Meyers, "Effective C++: 55 Specific Ways to Improve your Programs and Design", third edition.
My understanding is that the compiler will not generate constructors for the above case.
Edit 1:
This is not a duplicate of many constructor questions because:
This one has no data members.
This is not asking if a constructor is necessary, but what happens
when a constructor is not provided.
This is C++ language.
The compiler at least theoretically synthesizes a constructor even in this case. Even though you can't create an instance of this class, the constructor will be invoked in the process of creating a derived class (that overrides interface_function, so it can be instantiated).
Given that this is basically a pure interface class, the constructor probably won't do anything, so most compilers will probably optimize it out (quite possibly even when you don't tell it to optimize the code).
Are any constructors generated by the compiler?
Yes. Several. First, from [class.ctor]:
A default constructor for a class X is a constructor of class X that either has no parameters or else each
parameter that is not a function parameter pack has a default argument. If there is no user-declared constructor
for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted (8.4).
An implicitly-declared default constructor is an inline public member of its class. A defaulted default
constructor for class X is defined as deleted if:
Several bullet points follow, none of which apply. So we have the equivalent of:
My_Interface() = default;
Then, from [class.copy]:
If the class definition does not explicitly declare a copy constructor, a non-explicit 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).
So we have:
My_Interface(const My_Interface&) = default;
Also:
If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly
declared as defaulted if and only if
(9.1) — X does not have a user-declared copy constructor,
(9.2) — X does not have a user-declared copy assignment operator,
(9.3) — X does not have a user-declared move assignment operator, and
(9.4) — X does not have a user-declared destructor.
So we also have:
My_Interface(My_Interface&& ) = default;
If a constructor is generated, what would it's content be?
All three are generated, all three are = default;
If a constructor is generated, would it be eliminated by an optimization level?
None of the three constructors are trivial because My_Interface has a virtual function. As such, at the very least, the vtable will need to be initialized/copied. So something will have to happen, even if there aren't any members to initialize/copy/move.
Q1. Are any constructors generated by the compiler?
Answer: Yes. From the C++11 Standard:
12.1 Constructors
5 A default constructor for a class X is a constructor of class X that can be called without an argument. If
there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared
as defaulted (8.4). An implicitly-declared default constructor is an inline public member of its class.
I don't see anything in the standard that answers the other two questions. However, in your case, since there is a virtual member function, the default constructor must, at least, set the virtual table of the object.
Is this class:
class A {
public:
A() = default;
A(const A&) = delete;
};
trivially copyable? (At least clang seems to think so (live))
In particular, would
A a,b;
std::memcpy(&a, &b, sizeof(A));
invoke undefined behavior?
Context: This answer [deleted because proven wrong] plus its comment tree.
Update: The proposed resolution of CWG 1734, currently in "ready" status, would modify [class]/p6 to read:
A trivially copyable class is a class:
where each copy constructor, move constructor, copy assignment operator, and move assignment operator (12.8 [class.copy], 13.5.3
[over.ass]) is either deleted or trivial,
that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or move assignment operator,
and
that has a trivial, non-deleted destructor (12.4 [class.dtor]).
This renders classes like
struct B {
B() = default;
B(const B&) = delete;
B& operator=(const B&) = delete;
};
no longer trivially copyable. (Classes of this sort include synchronization primitives like std::atomic<T> and std::mutex.)
However, the A in the OP has a implicitly declared, non-deleted copy assignment operator that is trivial, so it remains trivially copyable.
The original answer for the pre-CWG1734 situation is preserved below for reference.
Yes, somewhat counterintuitively, it is trivially copyable. [class]/p6:
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).
[class.copy]/p12:
A copy/move constructor for class X is trivial if it is not
user-provided, its parameter-type-list is equivalent to the
parameter-type-list of an implicit declaration, and if
class X has no virtual functions (10.3) and no virtual base classes (10.1), and
class X has no non-static data members of volatile-qualified type, 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;
Similarly ([class.copy]/p25):
A copy/move assignment operator for class X is trivial if it is not
user-provided, its parameter-type-list is equivalent to the
parameter-type-list of an implicit declaration, and if
class X has no virtual functions (10.3) and no virtual base classes (10.1), and
class X has no non-static data members of volatile-qualified type, and
the assignment operator 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 assignment operator selected to copy/move that member is
trivial;
[class.dtor]/p5:
A destructor is trivial if it is not user-provided and if:
the destructor is not virtual,
all of the direct base classes of its class have trivial destructors, and
for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial
destructor.
[dcl.fct.def.default]/p5:
A function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration.
Indeed, this has been a source of problems for the committee itself, because under the current definition atomic<T> (along with mutexes and condition variables) would be trivially copyable. (And obviously, allowing someone to memcpy over an atomic or a mutex without invoking UB would be ... let's just say seriously problematic.) See also N4460.
Consider the following class:
class A
{
public:
std::string field_a;
std::string field_b;
}
Now consider the following copy construction:
A a1(a2);
The copy construction will adequately copy A despite the lack of of an explicit copy constructor because the copy constructors for std::string will be called by the compiler generated implicit copy constructor.
What I wish to know is, is the same true for move construction?
EDIT: Testing here shows that:
A a2(std::move(a1));
Will actually result in a copy construction, unless the specific move constructor:
A( A && other ) : a(std::move(other.a)) {}
Is defined.
EDIT EDIT
I pinged Stephan T Lavavej and asked him why VC 2012 doesn't seem to follow what draft 12.8 states regarding implicit move constructor generation. He was kind enough to explain:
It's more of a "feature not yet implemented" than a bug. VC currently
implements what I refer to as rvalue references v2.0, where move
ctors/assigns are never implicitly generated and never affect the
implicit generation of copy ctors/assigns. C++11 specifies rvalue
references v3.0, which are the rules you're looking at.
Yes, from the C++11 draft, 12.8:
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared
as defaulted if and only if
X does not have a user-declared copy constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator,
X does not have a user-declared destructor, and
the move constructor would not be implicitly defined as deleted.
The last condition is specified with more detail later:
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
for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.
Plainly speaking, the move constructor will be implicitly declared if:
The class does not have user-declared any of the other special member functions.
The move constructor can be sensibly implemented by moving all its members and bases.
Your class obviously complies with these conditions.
The compiler synthesizes a move constructor if it can and if there is no user-defined copy constructor. The restriction that no move constructor is synthesized if there is copy constructor is intended to avoid breaking existing code. Of course, all members need to be movable. The exact rules are a bit more involved.
I guess it is so, but I am looking for C++11 language lawyers to confirm my impression. Is it true that the following class
struct X{
X(){}
X(X const&)=default;
};
will not be automatically move-enabled, i.e., getting X(X&&) and operator=(X&&), because its copy constructor is "user-declared", even though it looks equivalent to
struct X{
};
which will get both X(X const&) and X(X&&) etc., implicitely declared and (trivially) defined on use.
From the standard:
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
4 - [...] A special member function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration. [...]
An explicit default can be combined with its declaration, or it can be separate:
struct S {
S();
};
S::S() = default;
In either case its (first) declaration makes it user-declared.
Yes, your defaulted copy assign operator precludes the implicit move ctor.
BTW putting =default is actually a definition. I remember trying to implement a pimpl idiom with std::unique_ptr and having to remove =default from headers and putting them in the implementation file because the destructor for unique_ptr needed the definition of the class it is trying to clean up.
A defaulted copy constructor is indeed "user-declared"; I think the addition of default was in fact the reason why they changed the term from "user-defined" to "user-declared".
That is correct, §12.8 sets the conditions when a move constructor gets implicitly declared and the presence of a user-declared copy constructor precludes that. You cannot have
user-declared copy constructor
user-declared copy assignment operator
user-declared move-assignment operator
user-declared destructor
This question already has answers here:
Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?
(3 answers)
Closed 2 years ago.
As per "Inside C++ Object Model" a copy constructor is generated (if not declared by the programmer) by the compiler only when at least any one of the below four conditions are true:
When the class contains a member object of a class for which a copy constructor exists (either explicitly declared by the class designer, as in the case of the previous String class, or synthesized by the compiler, as in the case of class Word)
When the class is derived from a base class for which a copy constructor exists (again, either explicitly declared or synthesized)
When the class declares one or more virtual functions
When the class is derived from an inheritance chain in which one or more base classes are virtual
Which means if I have a class with just constructor then copy constructor will not be provided by the compiler.
Lets take an example:
class test
{
test(){}
};
int main()
{
test obj1; //statement 1
test obj2(obj1); //statement 2
}
Above code works fine. Now the problem comes when I add the following lines in class test:
test(const test& rhs) = delete;
"= delete" ensures that copy constructor is not automatically provided. After adding above line I am getting an error for statement 2 which says Use of deleted function test::test(const test&).
My question is: as per "Inside C++ Object Model" I don't need a copy constructor for the above class so when I am explicitly saying not to generate a copy constructor (using delete) why am I getting an error? Since I was expecting that the compiler won't need a copy constructor for the above class.
I am using gcc version 4.6.3.
For class to be copyable, it needs to have a copy constructor. Whether you write your own, or compiler generates one for you, it doesn't matter — it has to be available for test a; test b(a); to be a valid operation.
You explicitly force compiler to delete the copy constructor — this is new version of old "make copy constructor private" trick. It disallows copying. So don't be surprised that you can't copy. Because you told the compiler to not allow it.
The standard word on implicitly generated copy constructors is [class.copy]/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.
and [class.copy]/13:
A copy/move constructor that is defaulted and not defined as deleted is implicitly defined if it is odr-used (3.2) or when it is explicitly defaulted after its first declaration. [Note:The copy/move constructor is implicitly defined even if the implementation elided its odr-use (3.2, 12.2). —end note] If the implicitly-defined constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined constructor isconstexpr.
So a copy-constructor is still generated for test, and its getting invoked by statement 2. I would believe that "Inside C++ Object Model" is talking about when a copy-constructor isn't trivial.
This line:
test obj2(obj1)
is trying to call the copy constructor.