According to these guidelines:
If the default destructor is needed, but its generation has been
suppressed (e.g., by defining a move constructor), use =default.
I can't imagine when code would be ill-formed without explicit default destructor in class which has move constructor.
Can somebody show me example confirms quote above?
struct S {
S() {};
S( S&& ) {}; // move ctor
};
int main() {
S s; // there is no need to declare dtor explicitly =default
}
I think it would be some kind of mistake, the implicit declaration of default destructor should have nothing to do with the definition of a move constructor.
From the standard, 12.4$4,5 Destructors [class.dtor]
4 If a class has no user-declared destructor, a destructor is
implicitly declared as defaulted (8.4). An implicitly-declared
destructor is an inline public member of its class.
5 A defaulted destructor for a class X is defined as deleted if:
(5.1) — X is a union-like class that has a variant member with a
non-trivial destructor,
(5.2) — any potentially constructed subobject has class type M (or
array thereof) and M has a deleted destructor or a destructor that is
inaccessible from the defaulted destructor,
(5.3) — or, for a virtual destructor, lookup of the non-array
deallocation function results in an ambiguity or in a function that is
deleted or inaccessible from the defaulted destructor.
Related
When I have a class that requires a virtual destructor is it enough to declare it virtual (and let the compiler generate the definition) or do I have to define it explicitly?
If the compiler generates a destructor for you:
§12.4/4 If a class has no user-declared destructor, a destructor is
implicitly declared as defaulted (8.4). An implicitly-declared
destructor is an inline public member of its class.
Note that you can do:
virtual ~Struct() = default;
6 Otherwise, the destructor is non-trivial. A destructor that is
defaulted and not defined as deleted is implicitly defined when it is
odr-used (3.2) to destroy an object of its class type (3.7) or when it
is explicitly defaulted after its first declaration.
Or:
virtual ~Struct() { }
Admittedly, the distinction between "user-declared" and "user-provided" is pretty confusing, so here's the relevant section:
§8.4.3/4 Explicitly-defaulted functions and implicitly-declared
functions are collectively called defaulted functions, and the
implementation shall provide implicit definitions for them (12.1 12.4,
12.8), which might mean defining them as deleted. A special member function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration. A user-provided
explicitly-defaulted function (i.e., explicitly defaulted after its
first declaration) is defined at the point where it is explicitly
defaulted; if such a function is implicitly defined as deleted, the
program is ill-formed.
You have to explicitly say virtual ~destructorName(). Just because you have a derived class does not make the bass class's destructor virtual by default.
There is a rule about cases when the copy/move constructor is implicitly deleted:
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:
[...]
— 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, or
[...]
Because I can't find an example reflecting the rule, it's not clear to me. Consider the following code:
struct A
{
~A() = delete;
};
struct B : A
{
A a;
B(){ }; //error error: attempt to use a deleted function B(){ };
B(const B&&) = delete;
};
B *b = new B;
int main() { }
DEMO
Because of deleted move constructor doesn't take a part in overload resolution, I expected the error would be something like "Copy constructor is implicitly deleted". But instead I got the error about deleted B(), which I defined explicitly. Couldn't you provide an example reflecting that rule?
Based only on the excerpt you've provided, the following is an example:
struct inner
{
~inner() = delete;
};
struct outer
{
inner inst;
// Can't destroy "inst"; outer now has an implicitly
// deleted destructor and copy/move constructor.
};
Look at 5th point: it is clearly saying that you have deleted your base class dtor so you are having this problem.
link: http://en.cppreference.com/w/cpp/language/default_constructor
Deleted implicitly-declared default constructor
The implicitly-declared or defaulted default constructor for class T is undefined (until C++11)defined as deleted (since C++11) if any of the following is true:
T has a member of reference type without a brace-or-equal
initializer. (since C++11)
T has a const member without user-defined default constructor or a
brace-or-equal initializer (since C++11).
T has a member (without a brace-or-equal initializer) (since C++11),
which has a deleted default constructor, or its default constructor
is ambiguous or inaccessible from this constructor.
T has a direct or virtual base which has a deleted default
constructor, or it is ambiguous or inaccessible from this
constructor.
T has a direct or virtual base which has a deleted destructor, or a
destructor that is inaccessible from this constructor.
T is a union with at least one variant member with non-trivial
default constructor.
(since C++11)
T is a union and all of its variant members are const.
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."
Look at the following code:
struct node
{
node();
//node(const node&); //#1
//node(node&&); //#2
virtual //#3
~node ();
node*
volatile //#4
next;
};
int main()
{
node m(node()); //#5
node n=node(); //#6
}
When compiled with gcc-4.6.1 it produces the following error:
g++ -g --std=c++0x -c -o node.o node.cc
node.cc: In constructor node::node(node&&):
node.cc:3:8: error: expression node::next has side-effects
node.cc: In function int main():
node.cc:18:14: note: synthesized method node::node(node&&) first required here
As I understand the compiler fails to create default move or copy constructor on line #6, if I uncomment either line #1 or #2 it compiles fine, that is clear. The code compiles fine without c++0x option, so the error is related to default move constructor.
However, what in the node class prevents default move constructor to be created? If I comment any of the lines #3 or #4 (i.e. make the destructor non-virtual or make data member non-volatile) it compiles again, so is it the combination of these two makes it not to compile?
Another puzzle, line #5 does not cause an compilation error, what is different from line #6?
Is it all specific for gcc? or gcc-4.6.1?
[C++11: 12.8/9]: 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.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise
would have invoked the move constructor may instead invoke a copy constructor. —end note ]
That's why your #3 is breaking the synthesis.
In addition, it's far from clear that volatile types (including your node* volatile) are trivially copyable; it could be concluded that it is implementation-defined whether they are or not and, in your case, it seems that they are not.
At the very least, GCC made it stop working quite deliberately in v4.7, with a proposal to backport into v4.6.1 that I can only presume went ahead...
So, given the following:
[C++11: 12.8/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
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.
... that's why your #4 is breaking the synthesis too, independently of #3.
As for #5, that's not actually a declaration of a node at all, but a declaration for a function called m — that's why it's not reproducing the symptoms related to construction of a node (this is known as the Most Vexing Parse).
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.