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.
Related
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.
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.
I know that among other things, a trivial constructor has to be implicitly defined.
Does this also apply when we use the default keyword?
Say we specify a T()=default constructor , is it considered user-provided or is it treated like an implicit constructor?
Yes, a user-declared constructor that is defaulted on its first declaration may be trivial:
struct Foo
{
Foo() = default;
Foo(int, int);
char x;
};
#include <type_traits>
static_assert(std::is_trivially_constructible<Foo>::value, "Works");
The example demonstrates how to define a POD class even in the presence of user-defined (non-default) constructors.
From the standard (12.1), "a default constructor is trivial if it is not user-provided" (plus conditions), and (8.4.2):
A function is user-provided if it is user-declared and not explicitly defaulted or
deleted on its first declaration.
However, note that triviality of a default constructor depends on more than just its declaration and definition. To expand the quote from 12.1:
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.
Implicit constructor is one provided by the compiler if you don't define one. That's a default constructor having no argument, unless you would like to have your own constructor with or without arguments to precisely control initialization of your object instance data members.
Code:
struct A{
int a;
virtual void f(){}
};
union B{
A ob;
};
Compile-time Error:
C:\to\main.cpp|9|error: member 'A B::ob' with constructor not allowed in union|
C:\to\main.cpp|9|error: member 'A B::ob' with copy assignment operator not allowed in union|
||=== Build finished: 2 errors, 0 warnings ===|
c++03 Standard:
An object of a class with a non-trivial constructor (12.1), a
non-trivial copy constructor (12.8), a non-trivial destructor (12.4),
or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a
member of a union, nor can an array of such objects. If a union
contains a static data member, or a member of reference type, the
program is ill-formed.
The standard doesn't say anything about an object of a class with a virtual function, and from the error, the compiler complain about constructor and copy-assignment operator which I didn't use. so is this a compiler bug ? Im using gcc .
The implicitly declared default constructor, copy constructor, and copy assignment operator for that struct are non-trivial because it has a virtual function, so you've broken those requirements.
A constructor is trivial if it is an implicitly-declared default constructor and if:
its class has no virtual functions (10.3) and no virtual base classes (10.1), and
[...]
A copy constructor for class X is trivial if it is implicitly declared and if
class X has no virtual functions (10.3) and no virtual base classes (10.1), and
[...]
A copy assignment operator for class X is trivial if it is implicitly declared and if
class X has no virtual functions (10.3) and no virtual base classes (10.1), and
[...]
The C++11 quote is similar (it just includes move constructors and assignment operators) but C++11 does not have the same requirement on members of unions.
Use C++11 if you can, it doesn't contain such constraint
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.