class Foo {
Foo(int val) { /* Do some initialization */ }
Foo() { /* Do nothing */ }
};
union Bar {
Foo foo;
};
That code generates this error:
error C2620: member 'Bar::foo' of union 'Bar' has user-defined constructor or non-trivial default constructor
I understand why you'd throw that error if the constructor actually did something, but the constructor here takes no parameters and does nothing. Is there any way I can stuff this class into a union? I've had to resort all the way to doing char foo[sizeof(Foo)] and would like a cleaner solution.
Originally from this question:
Initializing a union with a non-trivial constructor:
From C++03, 9.5 Unions, pg 162
A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class.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
So, your class is forbidden to be a member of the union.
This isn't allowed in the C++03 standard.
If objects with user defined default constructors were allowed in a union, the compiler couldn't decide which constructor to use, because all refer to the same memory location. Thus, objects with user defined constructors aren't allowed in unions.
The compiler will ignore the fact that your constructor doesn't do anything, because it might be defined elsewhere than the union.
You might get away with a C++0x constructor() = default;
Standard-specialists will likely answer this question more precisely than I do, but if I recall correctly, union members must be of POD type.
Use boost::variant if you want to use non-POD classes inside a union.
If your class has a user defined constructor, destructor or copy constructor, or assignment operator then it cannot be inside of a Union.
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.
In a C++ project that is full of objects (with proper behaviors) and relatively few of non-object-oriented structs (consisting of only data fields and no methods), I would like to prevent the accidental misuse of these structs, in which one might try to create a class inheriting from it.
According to my understanding, because these "POD" (plain old data) structs do not have a virtual destructor, it is not possible to properly delete a derived class object (if one is allowed to create it) via a pointer of the POD type.
This seems to make a good use case for the C++11 "final" keyword, which marks a class or struct as non-inheritable.
However, I wonder if the "final" keyword causes the struct to become non-POD?
I suspect that the standards documentation may have addressed this issue, but I am not intelligent enough to sift through the very long documentations to find out. Any useful pointers would be welcome.
Note: I am not interested in merely knowing that it passes the compilation of some compiler vendors. Passing compilation do not guarantee:
Whether the compiled code will execute correctly in all situations (especially when the technique is applied in a larger, more complex project),
Whether the C++ standards body intends this to be used in this way.
#include <iostream>
using namespace std;
struct Pod final
{
int a;
int b;
int c;
};
#if 0
class FailsBecauseCannotDeriveFromFinalAnything : public Pod
{
};
#endif
class ContainsSomethingFinalAsMember
{
public:
ContainsSomethingFinalAsMember() : pod() {}
private:
Pod pod;
};
int main()
{
std::cout << std::is_pod < Pod > :: value << std::endl;
return 0;
}
According to my understanding, because these "POD" (plain old data) structs do not have a virtual destructor, it is not possible to properly delete a derived class object (if one is allowed to create it) via a pointer of the POD type.
It's not possible given a raw pointer, but it is possible given a smart pointer object, such as std::shared_ptr or a std::unique_ptr with an appropriate deleter.
Since smart pointers were standardized, there are few excuses to continue following the poor practice of using the delete operator manually. Certainly, classes shouldn't be designed around compatibility with the delete operator. Each class interface should be designed with its particular uses in mind.
No, it's not a good practice to make every class either final or polymorphic.
However, I wonder if the "final" keyword causes the struct to become non-POD?
No, it's still POD. The requirements for POD are standard layout (in turn requiring no base class, no access specifiers between members, no virtual anything) and trivial special member functions (copy/move constructor, assignment operator, destructor).
However, the purpose of POD-ness is to allow you to use memcpy instead of properly constructing objects, which good C++ code would avoid doing.
Marking a class final does not change its POD status. Quoting C++11:
9 [class]:
6 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).
A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.
[ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base
classes.—end note ]
7 A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions (10.3) and no virtual base classes (10.1),
has the same access control (Clause 11) for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with
non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.
8 A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class. ...
10 A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no
non-static data members of type non-POD struct, non-POD union (or array of such types). ...
12.1 [class.ctor]
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.
Otherwise, the default constructor is non-trivial.
12.4 [class.dtor]
5 ... 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.
Otherwise, the destructor is non-trivial.
12.8 [class.copy]
12 A copy/move constructor for class X is trivial if it is not user-provided and if
— class X has no virtual functions (10.3) and no virtual base classes (10.1), 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;
otherwise the copy/move constructor is non-trivial.
25 A copy/move assignment operator for class X is trivial if it is not user-provided and if
class X has no virtual functions (10.3) and no virtual base classes (10.1), 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;
otherwise the copy/move assignment operator is non-trivial.
As you see, the definition of a POD struct does not take into account whether the class has the class-virt-specifier final.
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.
I am working on an application which in my opinion is rather poorly designed but that's another issue. There is a simple class in that app that I need to add a variable to. In this case I would like to add a STL stack to the class. Should be simple except that elsewhere the same class is used within a union and the compiler then complains that the class has a copy constructor. If I remove my added variable it compiles fine. My first thought was to add the stack as a pointer and then initialise it in the constructor but then the compiler complains that the class has a non trivial constructor.
My second (not ideal) thought was to add it as a pointer and initialise it outside the class. I know this isn't a good solution but I am up against some poorly designed code here which I cannot rewrite. However, this won't work because where I would need to initialise it, I cannot know if it has already been initialised or not. I cannot initialise the pointer in the class to NULL as even just doing that makes the compiler complain that the class now has a non-trivial constructor.
I guess my question is two-fold. Is there a way of adding a STL stack to a class that is used in a union? If not, is there a way of initialising a pointer to NULL in a class that is used in a union?
The class and union look something like this:
class MyClass
{
public:
std::stack<short> Index; // ideally what I wanted
}
union
{
int nNum;
MyClass myclass;
} u;
Please note: I cannot change the union. I accept that I cannot do what I was thinking. Is there any alternative no matter how silly it might sound. I cannot change the union or redesign the app as much as I would like to. This is the problem when you work on large apps that were first written around 18 years ago.
You could define the union as
union
{
int nNum;
MyClass * myclass;
} u;
This has the added benefit that int and pointer are the same size and it compiles.
Also, your example won't compile. It's missing ';' at the end of the class.
The answer for both questions is NO for C++03.
Since
9.5 Unions [class.union]
1
...
An object of a class with a non-trivial default 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.
You still can add constructor to the union that will init pointer instead of class ctor.
In C++11 however you can provide your own constructors for union, that should implement correct way to copy classes with non trivial constructors.
9.5 Unions [class.union]
2 A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. If a union contains a non-static data member of reference type the program is ill-formed. At most one non-static data member of a union may have a brace-or-equal-initializer. [Note: If any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be
user-provided or it will be implicitly deleted (8.4.3) for the union. — end note ]
You may also be interested in a following article
http://cpp11standard.blogspot.com/2012/11/c11-standard-explained-1-unrestricted.html
take two following classes:
class Test1{
public:
Test1()=default;
Test1(char in1,char in2):char1(in1),char2(in2){}
char char1;
char char2;
};
class Test2{
public:
Test2()=default;
Test2(char in1,char in2):char1(in1),char2(in2){}
private:
char char1;
char char2;
};
I know in c++0x both of these classes are considered as POD types and we can initialize objects of them using initializer lists as below:
Test1 obj1={'a','b'};//valid in c++0x
Test2 obj2={'a','b'};//valid in c++0x
But I wonder what the technical reason is that when we have different access specifiers in a class like below, it's not possible to use initializer list for initializing objects of that class and that class is not considered as a POD type ?
class Test{
public:
Test()=default;
Test(char in1,char in2):char1(in1),char2(in2){}
char char1;
private:
char char2;
};
Test obj={'a','b'};//invalid in c++0x
In case you don't know definition of PODs in c++0x:
A class/struct is considered a POD if it is trivial, standard-layout, and if all of its non-static members are PODs.
A trivial class or struct is defined as one that:
Has a trivial default constructor. This may use the default constructor syntax (SomeConstructor() = default;).
Has a trivial copy constructor, which may use the default syntax.
Has a trivial copy assignment operator, which may use the default syntax.
Has a trivial destructor, which must not be virtual.
A standard-layout class or struct is defined as one that:
Has only non-static data members that are of standard-layout type
Has the same access control (public, private, protected) for all non-static members
Has no virtual functions
Has no virtual base classes
Has only base classes that are of standard-layout type
Has no base classes of the same type as the first defined non-static member
Either has no base classes with non-static members, or has no non-static data members in the most derived class and at most one base class with non-static members. In essence, there may be only one class in this class's hierarchy that has non-static members.
In case you don't know what a trivial constructor or operator is:
Compiler generates a trivial one of each of following items for a class, in case it isn't user-declared:
Copy constructor, destructor and copy assignment operator.
And also if there's no user-declared constructor for a class, a trivial default constructor is generated for that class, in case there are any user-declared constructors you can use the syntax(SomeConstructor() = default;) to make your own trivial default constructor.
The "technical" reason is due to the following:
Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (C++0x §9.2/12).
So long as all the nonstatic data members have the same access control, their order is well-specified; otherwise their order is unspecified.
class Test{
public:
Test()=default;
Test(char in1,char in2):char1(in1),char2(in2){}
char char1;
private:
char char2;
};
considering above class following syntax is valid in c++0x:
Test obj={'a','b'};//valid in c++0x
The final proposal is here.