default behaviour of defined copy constructor c++ - c++

suppose I define a copy c'tor for a class B that inherits A and has a also member variables.
Inside the copt c'tor body I write some code, but in the initiallization list I don't call explicitly to A c'tor(also not to copy c'tor), and not initiallize the member variables.
In this case A default c'tor will be called defaultly before reaching B' copy c'tor body.
But what would be with the member variables?
would they be initillized with their default c'tor or with their copy c'tor with the arguement object's members (the argument object == given to B copy c'tor).
In addition, if there is calling inside the initiallization list to some members' copy c'tor/c'tor or to Parent class copy c'tor/c'tor - would that behaviour be changed?
I know that in case we don't define explicitly copy c'tor: Parent Class and members copy c'tor's are called.
What should I expect in here?

The base class subobject will be default initialized in that case. See [class.base.init]/8:
In a non-delegating constructor, if a given potentially constructed
subobject is not designated by a mem-initializer-id (including the
case where there is no mem-initializer-list because the constructor
has no ctor-initializer), then
if the entity is a non-static data member that has a brace-or-equal-initializer [..]
otherwise, if the entity is an anonymous union or a variant member (9.5), no initialization is performed;
otherwise, the entity is default-initialized (8.5).
And a potentially constructed subobject is defined in [special]/5:
For a class, its non-static data members, its non-virtual direct base
classes, and, if the class is not abstract (10.4), its virtual base
classes are called its potentially constructed subobjects.

If you write a copy-constructor and do not initialize a member variable then it will be default-initialized.
The same applies to base classes, in most ways they are treated the same as member variables.
Here is some sample code that will demonstrate:
#include <iostream>
using namespace std;
struct S
{
S() { cout << "S()\n"; }
S(S const &) { cout << "S(S&)\n"; }
};
struct T : S
{
T() {}
T(T const &t) {}
// you have to explicitly write this if you want it
// T(T const &t): S(t) {}
// ^^^^
};
int main()
{
T t;
T u(t);
}

Related

What is the difference between constructor "=default" and the compiler generated constructor in C++?

Example for code:
class Dog
{
private:
int x;
public:
Dog()=default;
};
Vs. this code:
class Dog
{
private:
int x;
};
What is the difference between the constructor that is "=default" (the first code) and the constructor that the compiler creates (like the second code)?
Dog() = default; is a user declared constructor (not to be confused with a user defined constructor). It is a defaulted default constructor. Typically you would use it when the class has other constructors but you still want the compiler to generate a default constructor (or rather a "defaulted default constructor". This is C++ terminology at its best. Note how the two "default"s have slightly different meaning).
A user declared constructor prevents a class from being an aggregate. From cppreference, only for C++20:
An aggregate is one of the following types:
array type
class type (typically, struct or union), that has
no private or protected direct non-static data members
no user-declared or inherited constructors
no virtual, private, or protected base classes
no virtual member functions
As an example, consider:
#include <iostream>
#include <type_traits>
class Dog {
int x;
public:
Dog()=default;
};
class Horse {
int x;
};
class Swan {
public:
int x;
};
class Cow {
public:
int x;
Cow() = default;
};
int main() {
std::cout << std::is_aggregate_v<Dog>;
std::cout << std::is_aggregate_v<Horse>;
std::cout << std::is_aggregate_v<Swan>;
std::cout << std::is_aggregate_v<Cow>;
}
Output
0010
The first two, Dog and Horse, resemble your two versions of Dog. They are not aggregates, because they have private members. Swan is an aggregate, but Cow is not, because it has a user declared constructor.
Something that works with aggregates, but not with non-aggregates, is designated initializers (same cppreference page):
Swan s{.x=3}; // OK
Cow c{.x=4}; // Error: Cow is not an aggregate
TL;DR: I am not aware of a difference between your two Dogs, but in general the presence of a user declared constructor can make a difference.
I'll limit the scope to a default constructor, as in the question's code and tag. For the most part, you'll get the same effect since = default; loosely means "give me the compiler-generated one". It's important to note what exactly having no declaration does:
If there is
no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared
as defaulted. An implicitly-declared default constructor is an inline public member of its class.
If your declaration changes any of these, it will no longer be the exact same as the implicit one. In the standard, Dog() = default; is a user-declared constructor, but not a user-provided constructor. There are a couple small differences between having a user-declared default constructor and having no constructor.
As mentioned, aggregates were fixed:
struct not_agg {
not_agg() = delete;
int x;
};
Before the fix, such a class could be created via aggregate initialization: not_agg{}. Naturally, this also extends to = default;. Per [dcl.init.aggr]:
An aggregate is an array or a class with
no user-declared or inherited constructors
There is also rationale given for this change in annex C:
Remove potentially error-prone aggregate initialization which may apply notwithstanding the
declared constructors of a class.
An interesting, but very tiny difference is that a class with a user-declared constructor is not allowed to have non-static data members of the same name as the class:
class c {
int c; // Okay
};
class c2 {
c2() = default;
int c2; // Error
};
This is due to [class.mem]/21:
In addition, if class T has a user-declared constructor, every non-static data member of class T shall have a name different from T.
Default declared constructors can be guarded with protected or private access. Not declared default constructors are always inline public members of their classes.
= default constructors are instantiated like usual member functions, may be inline or not, they have strong linkage references in the second case. The compiler creates not declared default constructors as inline member functions with weak linkage references.
As mentioned in the comments, =default constructors are user-defined constructors and their classes are not aggregate types.

Implicit copy constructor and inheritance

I know this kind of question has been asked many times, and I've read different answers about it, as well as some parts of the ISO standard.
But still, I need a few clarifications about the exact behaviour expected by the C++ standard.
Assuming this:
class A
{
public:
A( void ) {}
A( const A & a ) {}
};
class B: public A
{
public:
B( void ) {}
B( const B & b ) {}
};
I know that calling the copy constructor of the B class won't call the copy constructor of the A class, and that we can use an initialisation list in order to do it properly.
I also know about using using in order to inherit constructors.
But what does the standard exactly mandates about a derived class which does not provides explicitly a copy constructor, while the base class does:
class A
{
public:
A( void ) {}
A( const A & a ) {}
};
class B: public A
{};
I always thought the compiler would implicitly define a copy constructor for class B, thus hiding the copy constructor of class A, which won't be called.
However, looks like it's not the case, and the the A copy constructor is called.
Compiling with Clang on OS X 10.10.
So is this something mandatory, or something that can be implementation defined, meaning we should not rely on this behaviour?
In the C++ standard, I've found the following, but it's clearly not crystal-clear to me:
An inheriting constructor for a class is implicitly defined when it is
odr-used (3.2) to create an object of its class type (1.8). An
implicitly-defined inheriting constructor performs the set of
initializations of the class that would be performed by a user-written
inline constructor for that class with a mem-initializer-list whose
only mem-initializer has a mem-initializer-id that names the base
class denoted in the nested-name-specifier of the using-declaration
and an expression-list as specified below, and where the
compound-statement in its function body is empty (12.6.2).
I would really enjoy a clarification on it, in accordance with the standard, and also with multiple inheritance in mind.
From http://en.cppreference.com/w/cpp/language/copy_constructor (emphasis mine):
Implicitly-defined copy constructor
If the implicitly-declared copy constructor is neither deleted nor
trivial, it is defined (that is, a function body is generated and
compiled) by the compiler if odr-used. For union types, the
implicitly-defined copy constructor copies the object representation
(as by std::memmove). For non-union class types (class and struct),
the constructor performs full member-wise copy of the object's bases
and non-static members, in their initialization order, using direct
initialization.
So it seems that compiler generated copy constructor will call the base copy constructor just as it calls the copy constructors of the members.

Deleted destructor in the class appeared as a virtual/direct base class or as a type of non-static data member

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.

Why is a constructor necessary in a const member struct?

I have a code similar to this:
class AClass {
public:
struct AStruct { };
AClass(){}
private:
const AStruct m_struct;
};
int main() {
AClass a;
}
It throws this compilation error (with Clang LLVM version 5.1):
error: constructor for 'AClass' must explicitly initialize
the const member 'm_struct'
If I specify a C++11 default constructor for struct AStruct, I get the same error:
struct AStruct {
AStruct() = default;
};
However, this is solved by writing a constructor with an empty body:
struct AStruct {
AStruct(){} // fixed
};
Why do I need to specify an empty constructor? Isn't it automatically created with public access for structs?
Why does not the C++11 default constructor solve the problem?
From §8.5 [dcl.init]/7:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
The default constructor of AClass default-initializes the const member (see below), so that member must have a user-provided default constructor. Using = default does not result in a user-provided default constructor, as can be seen in §8.4.2 [dcl.fct.def.default]/4:
A function is user-provided if it is user-declared and not explicitly defaulted or
deleted on its first declaration.
The member is default-initialized per §12.6.2 [class.base.init]/8:
In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
— if the entity is a non-static data member that has a brace-or-equal-initializer , the entity is initialized as specified in 8.5;
— otherwise, if the entity is an anonymous union or a variant member (9.5), no initialization is performed;
— otherwise, the entity is default-initialized (8.5).
Stolen from #chris's answer we have this paragraph: §8.5 [dcl.init]/7:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
We can then construct a completely ridiculous case that illustrates this restriction:
struct Foo {};
int main() {
const Foo f;
}
which fails to compile in clang, as the standard dictates. Your code is simply this, but as a member variable of another class/struct.
We can even do this:
struct Foo {int x = 3;};
int main() {
const Foo f;
}
where all the data is obviously initialized. This last example convinces me that this is a defect in the standard.
The thought was probably something to do with POD types being uninitialized and const, but the wording blocks code that is unrelated. Default constructors in modern C++ are often more than good enough, and forcing Foo(){} is poor form.

Initializing a union with a non-trivial constructor

I have a structure which I create a custom constructor to initialize the members to 0's. I've seen in older compilers that when in release mode, without doing a memset to 0, the values are not initialized.
I now want to use this structure in a union, but get errors because it has a non-trivial constructor.
So, question 1. Does the default compiler implemented constructor guarantee that all members of a structure will be null initialized? The non-trivial constructor just does a memset of all the members to '0' to ensure a clean structure.
Question 2: If a constructor must be specified on the base structure, how can a union be implemented to contain that element and ensure a 0 initialized base element?
Question 1: Default constructors do initialize POD members to 0 according to the C++ standard. See the quoted text below.
Question 2: If a constructor must be specified in a base class, then that class cannot be part of a union.
Finally, you can provide a constructor for your union:
union U
{
A a;
B b;
U() { memset( this, 0, sizeof( U ) ); }
};
For Q1:
From C++03, 12.1 Constructors, pg 190
The implicitly-defined default constructor performs the set of initializations of the
class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.
From C++03, 8.5 Initializers, pg 145
To default-initialize an object of type T means:
if T is a non-POD class type
(clause 9), the default constructor
for T is called (and the
initialization is ill-formed if T
has no accessible default
constructor);
if T is an array type, each element is default-initialized;
otherwise, the object is zero-initialized.
To zero-initialize an object of type T means:
if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
if T is a non-union class type, each non static data member and each base-class subobject is zero-initialized;
if T is a union type, the object’s first named data member is zero-initialized;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
For Q2:
From C++03, 12.1 Constructors, pg 190
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
all the direct base classes of its class have trivial constructors, and
for all the nonstatic data members of its class that are of class type (or array
thereof), each such class has a 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
Things changed for the better in C++11.
You can now legally do this, as described by Stroustrup himself (I reached that link from the Wikipedia article on C++11).
The example on Wikipedia is as follows:
#include <new> // Required for placement 'new'.
struct Point {
Point() {}
Point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U {
int z;
double w;
Point p; // Illegal in C++03; legal in C++11.
U() {new(&p) Point();} // Due to the Point member, a constructor
// definition is now *required*.
};
Stroustrup goes into a little more detail.
AFAIK union members may not have constructors or destructors.
Question 1: no, there's no such guarantee. Any POD-member not in the constructor's initialization list gets default-initialized, but that's with a constructor you define, and has an initializer list. If you don't define a constructor, or you define a constructor without an initializer list and empty body, POD-members will not be initialized.
Non-POD members will always be constructed via their default constructor, which if synthesized, again would not initialize POD-members. Given that union members may not have constructors, you'd pretty much be guaranteed that POD-members of structs in a union will not be initialized.
Question 2: you can always initialize structures/unions like so:
struct foo
{
int a;
int b;
};
union bar
{
int a;
foo f;
};
bar b = { 0 };
As mentioned in Greg Rogers' comment to unwesen's post, you can give your union a constructor (and destructor if you wish):
struct foo
{
int a;
int b;
};
union bar
{
bar() { memset(this, 0, sizeof(*this)); }
int a;
foo f;
};
Can you do something like this?
class Outer
{
public:
Outer()
{
memset(&inner_, 0, sizeof(inner_));
}
private:
union Inner
{
int qty_;
double price_;
} inner_;
};
...or maybe something like this?
union MyUnion
{
int qty_;
double price_;
};
void someFunction()
{
MyUnion u = {0};
}
You'll have to wait for C++0x to be supported by compilers to get this. Until then, sorry.