C++ class instance not initialized but no compile error, why - c++

My question is about the following code:
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Blob {
public:
int age;
void hello() { printf("hello\n"); }
};
void test_case() {
Blob a;
//a.hello(); //(1)
cout << a.age << endl;
}
int main() {
test_case();
return 0;
}
if I comment out (1), it compile success. If uncomment out (1), compile error occur, e.g. in VS2017 it complains "using an unintialized local variable 'a'".
I've searched in search engine for a while and now only know the following 4 cases that the compiler will automatically help me define the default constructor:
a class member is an instance of a class (say B), and class B have defined default constructor
a class is derived from another class (say B), and B has defined default constructor
a class has virtual function
any combination of the previous 3 cases.
I'm curious that, if I comment out (1), will the compiler add a definition of constructor for the class Blob?

In fact it has nothing to do with comment out or not a.hello();, Blob always has a generated default constructor, otherwise Blob a; won't compile.
(emphasis mine)
If no user-declared constructors of any kind are provided for a class
type (struct, class, or union), the compiler will always declare a
default constructor as an inline public member of its class.
If the implicitly-declared default constructor is not defined as
deleted, it is defined (that is, a function body is generated and
compiled) by the compiler if odr-used, and it has the same effect as a
user-defined constructor with empty body and empty initializer list.
As the result, a.age is default-initialized to indeterminate value, any access to it (like cout << a.age;) leads to UB.
3) when a base class or a non-static data member is not mentioned in a
constructor initializer list and that constructor is called.
otherwise, nothing is done: the objects with automatic storage
duration (and their subobjects) are initialized to indeterminate
values.
It depends on your intent; as the workaround you can add a user-defined default constructor.
class Blob {
public:
int age;
void hello() { printf("hello\n"); }
Blob() : age(42) {}
};

There are 2 points here.
First is the Undefined Behaviour question. As you do not initialize age, it contains an indeterminate value which leads to UB if you use it (see songyuanyao's answers for more details on that). Adding an additional instruction does not change anything to that point.
Next is the compiler message. Compilers are not required to issue any warning facing UB. Yours is not specially consistent if it raises the error in only one case, but the programmer is supposed to never write UB. So you cannot really blame the compiler for not issuing the warning.
TL/DR: do not expect a C++ compiler to alway issue warning when you write incorrect code. Having no warning is a necessary condition, but not a sufficient one.

Related

Location of compiler-generated class methods

EDIT: Added a field to the example class to make it non-trivially-destructible, and a clarification that it was not meant to be the point of the question.
Consider a simple class with no user-declared destructor, e.g.
struct A {
std::string s;
};
Note that the actual field doesn't matter - it's only here to make the classes non-trivially-destructible, so that it doesn't distract. In other words, imagine it's a "normal" everyday class, not exceptional in any way.
In this case, the compiler is going to generate the destructor for us. The overall question is: when exactly is this destructor generated and where is its body placed?
To be more specific:
does the compiler actually generate any source code? and if so, where is this source code placed?
if no actual source code is generated, and we move directly to some internal represention / machine code, the questions are the same - when is the generation triggered, and where is its representation stored?
The practical motivation for this question is the issue of using unique_ptr with incomplete types, as in std::unique_ptr with an incomplete type won't compile or related questions. The solution is to prevent the compiler from generating the destructor on its own, and to precisely control the location by ourselves, so that the generation happens only after the complete type definition has been seen. And while most answers mention that it's generated "too early", I couldn't find any specifics on when exactly does it happen.
I'd speculate that the destructor (and other auto-generated members) would be placed at the end of class definition, right before the closing brace, but it's just a guess.
Any normative references would be much appreciated as well.
Please also note that this question is not about the contents of the destructor - it's not about what it does, it's about where it's located.
tl;dr
Implicitly declared destructors are declared public inline and at the end of the class definition, e.g.:
struct A {
std::string s;
public: inline ~A(); // implicit destructor
};
Destructors only get defined when they're used in the current translation unit.
The Destructor Body will be able to use all types that were accessible at the class definition and additionally all types that were accessible at the point were the class was first used.
How the compiler generates the code for the destructor and where it'll ultimately end up with is not easily answerable, since it depends on the compiler, compilation flags and even the code that gets compiled.
Long Explanation
What the C++ Standard says
11.4.7 Destructors
If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as
defaulted (9.5). An implicitly-declared prospective destructor is an inline public member of its class.
11.4.4 Special member functions
Default constructors (11.4.5.2), copy constructors, move constructors (11.4.5.3), copy assignment operators,
move assignment operators (11.4.6), and prospective destructors (11.4.7) are special member functions.
An implicitly-declared special member function is declared at the closing } of the class-specifier. Programs
shall not define implicitly-declared special member functions.
So if you don't add a destructor to your class you'll get an implicit one that will be an inline public member of the class and declared at the the end of the class definition.
Note that it is only declared - not defined - so the compiler will not check if the destructor would compile at this point.
i.e. in your example it could look like this:
struct A {
std::string s;
// it's only *declared*, not defined
inline ~A();
};
The compiler only needs to define the destructor if it is used somewhere.
So unless you use A somewhere it's implicit destructor will never be defined and you won't get any errors.
So the following is valid c++ even though the destructor of Foo would not be able to be compiled because Miau is never defined:
struct Miau;
class Foo {
public:
std::unique_ptr<Miau> miauPtr;
};
// Miau never defined
// Foo never used
The actual point where the compiler needs to define the destructor is:
11.4.7 Destructors
A destructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (6.3) or
when it is explicitly defaulted after its first declaration.
So the compiler needs to generate a definition for the destructor when you actually use it or when you explicitly default it (e.g. A::~A() = default;, which in your case doesn't apply)
At this point you would actually get an error if your implicit destructor doesn't compile (e.g. because one of the members uses an incomplete type)
The declarations that will be visible to the implicitly defined destructor are defined as follows:
10.6 Instantiation context
During the implicit definition of a defaulted function (11.4.4, 11.11.1), the instantiation context is the union
of the instantiation context from the definition of the class and the instantiation context of the program
construct that resulted in the implicit definition of the defaulted function.
So everything that was accessible at the point of the class definition and additionally everything that is accessible from the point where you first used the class is visible to the destructor.
e.g.:
#include <memory>
#include <string>
struct Miau;
struct Foo {
std::unique_ptr<Miau> miauPtr;
};
struct Miau { std::string s; };
void useFoo() {
Foo f; // first usage of Foo
// this forces the compiler to define the destructor for Foo.
// it'll compile without any error because at this point Miau
// is already defined.
}
godbolt example
Note that this is only the case for implicitly defined destructors.
If you explicitly define the destructor (even if you default it), then instead of the point of first use the point where you explicitly defined it will be used instead.
e.g. if you replace Foo from the example above with:
// ok - implicit declaration and implicit definition
struct Foo {
std::unique_ptr<Miau> miauPtr;
};
// ok - explicit declaration and implicit definition
struct Foo {
~Foo() = default;
std::unique_ptr<Miau> miauPtr;
};
// error - explicit declaration and explicit definition
struct Foo {
~Foo();
std::unique_ptr<Miau> miauPtr;
};
Foo::~Foo() = default; // if Miau is not defined before this line we'll get an error
godbolt example
What's up to the compilers
The standard only defines how the destructor will be declared in the class body and when it needs to be defined.
Everything else is the decision of the compiler - how he generates the code for the destructor (be it source code, some internal representation or directly bytecode) or where the code then gets stored.
So you might up with no code at all for the destructor when it gets inlined everywhere.
Or you might get one version of the destructor for each translation unit.
Or a single version of the destructor that gets called by all the translation units.
This might also depend on the compilation flags you use and even on the code itself - so without a concrete example there is no clear answer to what the compiler will do with the implicit destructor.
The only guarantee you have is that the code of the destructor will get executed when an A is destroyed, apart from that everything is in the hands of the compiler.

Linker error for different declarations of default constructors

I have been playing around with default constructors and noticed a weird behavior (from my point of view).
When I declare A() = default, I get no linker error.
struct A
{
int a;
A() = default;
};
A a; // no linker error
However, when I declare A(); I get it.
struct A
{
int a;
A();
};
A a; // linker error - undefined reference to `A::A()`
Questions:
What's the difference between the two?
And if A(); produces a linker error, why is it supported in the first place? Any practical applications?
UPDATE (Follow-up Question)
For A(); why can't it be implicitly defined by the compiler if no definition is specified by the user?
In the first case the compiler itself defines the constructor.
Take into account that in the first case the constructor declaration is at the same its definition.
In the second case as the constructor is a user-defined constructor then it is the user who must to define the constructor. In the second case there is only a declaration of the constructor.
Take into account that you can declare a constructor and then define it using the specifier default.
For example
#include <iostream>
struct A
{
int a;
A();
};
A::A() = default;
int main()
{
A a;
return 0;
}
The purpose of writing
A();
is to declare to the compiler that a definition of what A() should actually do will be given somewhere else (by you!), and if it is given in another compilation unit (cpp-file) the linker is responsible for finding this definition.
A() = default;
is a way of declaring to the compiler that it should create a definition of what should be done on construction of an A, automatically, subject to the rules of the language. So because the definition is already given, the linker won't complain about not finding it.
Why is it supported to declare without defining A() in the first place? Because you want to be able to compile different cpp-files independently. Otherwise you would always have to compile all your code, even if 99% of it hasn't changed.
The construction of an A will most likely be defined in "A.cpp". If you have completed the design of your struct A then ideally "A.cpp" will be compiled once and never again. If you construct an A in a different class/struct/compilation unit "B.cpp" then the compiler can trust in the existence of a definition for A() while compiling "B.cpp", without knowing what the definition actually looks like.
As to the follow-up question, "why it can't be defined implicitly": this is probably a misunderstanding about why errors occur. Compiler/linker errors do not occur to punish you. They don't mean that the compiler is pretending not to be able to do something although it can. Errors occur in order to remind you that you are breaking your own promises and any attempt by the compiler or the linker to repair that, might be possible, but is most likely not going to work as you want it to, because there are signs that you have lost track of your own requirements.
That being said, A() could be defined implicitely. But if you write "A();" you are explicitely telling the compiler not to do it implicitly, and telling the linker to remind you, if you should ever forget to define it. This doesn't only apply to constructors but to every kind of method, most of which have no natural sense of what it means to define them implicitely. What is the default definition of "A.makeMoney"? It is non-trivial and by writing A.makeMoney(); you are telling the compiler: "trust me, I'm gonna define somewhere how it's gonna be done".
(15.1 Constructors)
A default constructor for a class X is a constructor of class X for
which each parameter that is not a function parameter pack has a
default argument (including the case of a constructor with no
parameters). If there is no user-declared constructor for class X, a
non-explicit constructor having no parameters is implicitly declared
as defaulted (11.4). An implicitly-declared default constructor is an
inline public member of its class.
Purpose of
A() = default;
is to tell compiler to create default constructor, as if no constructor was defined by user. Consider this case
struct A
{
int a;
A(int v): a(v) {}
};
A a; // compiler error, no default constructor
If ANY constructor was declared by user, default one will be gone.
By adding A() = default; to that declaration you would allow class A to be constructed that way. It is explicitly-defaulted (11.4.2)
A function definition whose function-body is of the form = default ;
is called an explicitly-defaulted definition. A function that is
explicitly defaulted shall
(1.1) — be a special member function,
(1.2) — have the same declared function type (except for possibly
differing ref-qualifiers and except that in the case of a copy
constructor or copy assignment operator, the parameter type may be
“reference to non-const T”, where T is the name of the member
function’s class) as if it had been implicitly declared, and
(1.3) — not have default arguments.
Methods follow same linking rules as any functions with external linking. If you declare any method in class body and your code refers to that method (in case of constructor - by creating object of this class), you have to define it in any compilation module of same program, otherwise program will be ill-formed.
struct A
{
A() = default;
Here, you're saying that the constructor should be implemented automagically, i.e. any class members that have a default constructor will be initialized with it, and any class members that don't have a default constructor will be left uninitialized.
struct A
{
A();
Here, you're saying that you will implement a default constructor. So you have to implement it. E.g.
A::A()
: a(42)
{
}
This is additional information, and is supplemental to the answer provided by others.
There is a difference w.r.t. the context of special member functions, when we use the terms such as defaulted, undeclared and deleted.
When a special member function is:
undeclared : It does not participate in overload resolution. To use this functionality, just don't declare the special member function.
deleted : It participates in overload resolution. It prevents compilation, if used anywhere. To use this functionality, the keyword is delete
defaulted : It participates in overload resolution. The default, compiler generated code is provided as the definition. To use this functionality, the keyword is default
There is an interesting talk by Howard Hinnat on the same, where he explains when the special member functions are defaulted/deleted/undeclared - https://www.youtube.com/watch?v=vLinb2fgkHk
Adding more info for A::A();
Referring to class.ctor/1.2:
The class-name shall not be a typedef-name. In a constructor
declaration, each decl-specifier in the optional decl-specifier-seq
shall be friend, inline, explicit, or constexpr.
[ Example:
struct S {
S(); // declares the constructor
};
S::S() { } // defines the constructor
— end example ]
Thus, A(); is just a declaration and not a definition causing:
undefined reference to `A::A()'

C++ initializing pointer/reference/copy nuances

Context: Embedded programming and initializer list nuances, especially the one that I think should invoke the copy constructor.
Question: Will the instantiation of a class in another class's initializer list to initialize a value-held member variable invoke the copy constructor?
Example provided below where TestClassCopy has a member variable TestMember held by value as opposed to pointer or reference. This cppreference page does not seem to cover this sufficiently in the examples provided.
Bonus question: Will a copy constructor invoked in an initializer list produce any time/space perf impact? Seems like a compiler should be able to optimize this away if the C++ spec allows.
Here's the code (build tested with the VS2015 toolchain):
TestMember.h (not showing TestMember.cpp for space reasons)
#pragma once
#include <stdint.h>
class TestMember {
public:
TestMember(uint8_t);
private:
uint8_t m_value;
};
TestClassCopy.h
#pragma once
#include "test_member.h"
class TestClassCopy {
public:
TestClassCopy();
virtual ~TestClassCopy();
private:
TestMember m_member;
};
TestClassCopy.cpp
#include "test_class_copy.h"
TestClassCopy::TestClassCopy() :
m_member(TestMember(255)) { // invokes copy constructor yes?
}
TestClassCopy::~TestClassCopy() {
}
For completeness, other things where I might be making assumptions I shouldn't:
For a member pointer to a TestMember, a 'new' in the initializer list and a 'delete' in the destructor should be sufficient.
For a member reference, my understanding is that there's even more nuance in that if the reference is passed into the constructor, you can just assign it (since lifetime is managed outside of the initializer list). However, if the TestMember is instantiated in the initializer list (into a reference), then that's a no-no since the TestMember temporary goes away after the initialization is complete.
TestMemberReference.h
#pragma once
class TestMember;
class TestClassReference {
public:
TestClassReference();
virtual ~TestClassReference();
private:
TestMember& m_member;
};
TestMemberReference.cpp
#include "test_class_reference.h"
#include "test_member.h"
TestClassReference::TestClassReference() :
m_member(TestMember(255)) { // ew, don't do this; TestMember temporary will go out of scope
}
TestClassReference::~TestClassReference() {
}
This cppreference page does not seem to cover this sufficiently in the examples provided
that cppreference page says "Initializes the base or member named by class-or-identifier using direct initialization" and if you click that, you can read that, as of C++17,
if the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather that a temporary materialized from it, is used to initialize the destination object: see copy elision
so the answer is: in C++17 no copy constructor is called. Before C++17, a copy constructor could technically be called, but copy elision eliminated that call. You could still observe it, as proof, by compiling your example with g++ -fno-elide-constructors -O0 -std=c++14

Is it true that a default constructor is synthesized for every class that does not define one?

If the class doesn't have the constructor, will the compiler make one default constructor for it ?
Programmers new to C++ often have two common misunderstandings:
That a default constructor is synthesized for every class that does
not define one
from the book Inside the C++ Object Model
I am at a loss...
This is well explained in the section from which this quote is taken. I will not paraphrase it in its entirety, but here is a short summary of the section content.
First of all, you need to understand the following terms: implicitly-declared, implicitly-defined, trivial, non-trivial and synthesized (a term that is used by Stanley Lippman, but is not used in the standard).
implicitly-declared
A constructor is implicitly-declared for a class if there is no user-declared constructor in this class. For example, this class struct T { }; does not declare any constructor, so the compiler implicitly declares a default constructor. On the other hand, this class struct T { T(int); }; declares a constructor, so the compiler will not declare an implicit default constructor. You will not be able to create an instance of T without parameters, unless you define your own default constructor.
implicitly-defined
An implicitly-declared constructor is implicitly-defined when it is used, i.e. when an instance is created without parameters. Assuming the following class struct T { };, the line T t; will trigger the definition of T::T(). Otherwise, you would have a linker error since the constructor would be declared but not defined. However, an implicitly-defined constructor does not necessarily have any code associated with it! A default constructor is synthesized (meaning that some code is created for it) by the compiler only under certain circumstances.
trivial constructor
An implicitly-declared default constructor is trivial when:
its class has no virtual functions and no virtual base classes and
its base classes have trivial constructors and
all its non-static members have trivial constructors.
In this case, the default compiler has nothing to do, so there is no code synthesized for it. For instance, in the following code
struct Trivial
{
int i;
char * pc;
};
int main()
{
Trivial t;
}
the construction of t does not involve any operations (you can see that by looking at the generated assembly: no constructor is called to construct t).
non-trivial
On the other hand, if the class does not meet the three requirements stated above, its implicitly-declared default constructor will be non-trivial, meaning that it will involve some operations that must be performed in order to respect the language semantics. In this case, the compiler will synthesize an implementation of the constructor performing these operations.
For instance, consider the following class:
struct NonTrivial
{
virtual void foo();
};
Since it has a virtual member function, its default constructor must set the virtual table pointer to the correct value (assuming the implementation use a virtual method table, of course).
Similarly, the constructor of this class
struct NonTrivial
{
std::string s;
};
must call the string default constructor, as it is not trivial. To perform these operations, the compiler generates the code for the default constructor, and calls it anytime you create an instance without parameters. You can check this by looking at the assembly corresponding to this instantiation NonTrivial n; (you should see a function call, unless the constructor has been inlined).
Summary
When you don't provide any constructor for your class, the compiler implicitly declares a default one. If you try to use it, the compiler implicitly defines it, if it can (it is not always possible, for instance when a class has a non-default-constructible member). However, this implicit definition does not imply the generation of any code. The compiler needs to generate code for the constructor (synthesize it) only if it is non-trivial, meaning that it involves certain operations needed to implement the language semantics.
N.B.
Stanley B Lippman's "Inside the C++ object model" and this answer deals with (a possible) implementation of C++, not its semantics. As a consequence, none of the above can be generalized to all compilers: as far as I know, an implementation is perfectly allowed to generate code even for a trivial constructor. From the C++ user point of view, all that matters is the "implicitly-declared/defined` aspect (and also the trivial/non-trivial distinction, as it has some implications (for instance, an object of a class with non-trivial constructor cannot be a member of a union)).
I think the misconception is:
That a default constructor is synthesized for every class that does not define one
That people think the default constructor, which accepts no arguments, will always be generated if you don't declare it yourself.
However, this is not true, because if you declare any constructor yourself, the default one will not be automatically created.
class MyClass {
public:
MyClass(int x) {}; // No default constructor will be generated now
};
This will lead to problems like when beginners expect to use MyClass like this:
MyClass mc;
Which won't work because there is no default constructor that accepts no args.
edit as OP is still a little confused.
Imagine that my MyClass above was this:
class MyClass {
};
int main() {
MyClass m;
}
That would compile, because the compiler will autogenerate the default constructor MyClass() because MyClass was used.
Now take a look at this:
#include <iostream>
class MyClass {
};
int main() {
std::cout << "exiting\n";
}
If this were the only code around, the compiler wouldn't even bother generating the default constructor, because MyClass is never used.
Now this:
#include <iostream>
class MyClass {
public:
MyClass(int x = 5) { _x = x; }
int _x;
};
int main() {
MyClass m;
std::cout << m._x;
}
The compiler doesn't generate default constructor MyClass(), because the class already has a constructor defined by me. This will work, and MyClass(int x = 5) works as your default constructor because it can accept no arguments, but it wasn't generated by the compiler.
And finally, where beginners might run into a problem:
class MyClass() {
public:
MyClass(int x) { _x = x; }
int _x;
};
int main() {
MyClass m;
}
The above will throw you an error during compilation, because MyClass m needs a default constructor (no arguments) to work, but you already declared a constructor that takes an int. The compiler will not generate a no-argument constructor in this situation either.
A default constructor is synthesized for every class that does not define one if:
The code using the class needs one & only if
There is no other constructor explicitly defined for the class by you.
All the upvoted answers thus far seem to say approximately the same thing:
A default constructor is synthesized for every class that does not have any user-defined constructor.
which is a modification of the statement in the question, which means
A default constructor is synthesized for every class that does not have a user-defined default constructor.
The difference is important, but the statement is still wrong.
A correct statement would be:
A default constructor is synthesized for every class that does not have any user-defined constructor and for which all sub-objects are default-constructible in the context of the class.
Here are some clear counter-examples to the first statement:
struct NoDefaultConstructor
{
NoDefaultConstructor(int);
};
class Surprise1
{
NoDefaultConstructor m;
} s1; // fails, no default constructor exists for Surprise1
class Surprise1 has no user-defined constructors, but no default constructor is synthesized.
It doesn't matter whether the subobject is a member or a base:
class Surprise2 : public NoDefaultConstructor
{
} s2; // fails, no default constructor exists for Surprise2
Even if all subobjects are default-constructible, the default constructor has to be accessible from the composite class:
class NonPublicConstructor
{
protected:
NonPublicConstructor();
};
class Surprise3
{
NonPublicConstructor m;
} s3; // fails, no default constructor exists for Surprise3
Yes a default constructor is always there by default if you don't define a constructor of your own (see the default constructor section here).
http://www.codeguru.com/forum/archive/index.php/t-257648.html
Quote:
The following sentense are got from the book "Inside the C++ object model" , written by Stanley B. Lippman.
There are four characteristics of a class under which the compiler
needs to synthesize a default constructor for classes that declare no
constructor at all. The Standard refers to these as implicit,
nontrivial default constructors. The synthesized constructor fulfills
only an implementation need. It does this by invoking member object or
base class default constructors or initializing the virtual function
or virtual base class mechanism for each object. Classes that do not
exhibit these characteristics and that declare no constructor at all
are said to have implicit, trivial default constructors. In practice,
these trivial default constructors are not synthesized. ...
Programmers new to C++ often have two common misunderstandings:
That a default constructor is synthesized for every class that does
not define one
That the compiler-synthesized default constructor provides explicit
default initializers for each data member declared within the class
As you have seen, neither of these is true.

What is hidden slicing copy constructor?

This question is because of this question and the comments.
This example :
#include <iostream>
struct A {
A(int value) : m_value(value) { }
int m_value;
};
struct B : A {
B(int value) : A (value) { }
};
int main()
{
try {
throw B(5);
}
catch(A) {
std::cout << "A catch" << std::endl;
}
catch(B) {
std::cout << "B catch" << std::endl;
}
}
when compiled using g++ 4.6.1 like this :
g++ exception_slicing.cpp -ansi -pedantic -Wall -Wextra
produces next output :
exception_slicing.cpp: In function 'int main()':
exception_slicing.cpp:20:5: warning: exception of type 'B' will be caught [enabled by default]
exception_slicing.cpp:17:5: warning: by earlier handler for 'A' [enabled by default]
and the output is A catch.
I understand that the 1st catch block triggered because of the slicing problem.
Where does it say about hidden copy constructor in the base class?
Where does it say about this behaviour?
PS1 Please provide answers with quote from the standard.
PS2 And I am aware that the exceptions should be handled by const reference.
In your case, same warning pops up even if you catch by const reference, where no slicing occurs. Your problem is that since B is a public subclass of A ==> every B is-a A, so it can be caught by the first handler. You should probably order handlers from most specific to least specific.
Also, you're printing "A" in both catch blocks.
1 Where does it say about hidden copy constructor in the base class?
It's not hidden as much as it is implicit.
Using n3290:
§ 12 Special member functions
1/ The default constructor (12.1), copy constructor and copy assignment operator (12.8), move constructor and move assignment operator (12.8), and destructor (12.4) are special member functions. [ Note: The implementation will implicitly declare these member functions for some class types when the program does not explicitly declare them. The implementation will implicitly define them if they are odr-used (3.2). See 12.1, 12.4 and 12.8. —end note ]
So, let us follow the pointer:
§ 12.8 Copying and moving class objects
7/ If the class definition does not explicitly declare a copy constructor, one is declared implicitly. [...]
8/ The implicitly-declared copy constructor for a class X will have the form
X::X(const X&)
if
— each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
— for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&.
Otherwise, the implicitly-declared copy constructor will have the form
X::X(X&)
And there you have it. In your case, there is a copy constructor A::A(A const&) implicitly defined for you.
2 Where does it say about this behaviour?
Unsuprisingly, in the part devoted to exception handling.
§ 15.3 Handling an exception
3/ A handler is a match for an exception object of type E if
[...]
— the handler is of type cv T or cv T& and T is an unambiguous public base class of E, or
[...]
It is very similar to parameter passing in functions. Because B publicly inherits from A, an instance of B can be passed as a A const&. Since a copy constructor is not explicit (hum...), B is convertible into a A, and therefore, as for functions, a B can be passed where a A (no reference) is expected.
The Standard goes on:
4/ The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.
Which is really what this warning is all about.
The example you give doesn't really demonstrate slicing, it's simply warning you that since B is-a A, the catch(A) effectively hides the catch(B).
To see the effects of slicing, you would have to do something with the A in the catch:
catch(A a) {
// Will always print class A, even when B is thrown.
std::cout << typeid(a).name() << std::endl;
}
Where does it say about hidden copy constructor in the base class?
The standard says nothing about a "hidden copy constructor." It does say stuff about an implicitly-defined copy constructor.
If you must have a quote:
If the class definition does not explicitly declare a copy constructor, there is no user-declared move constructor, one is declared implicitly.
In C++11, this can be declared default or delete, depending on the contents of the class in question. I'm not going to copy and paste the full list of reasons why a class might not be copyable. But suffice it to say, your class will get a default copy constructor.
Where does it say about this behaviour?
About what behavior? The behavior you see is exactly what you would expect to see in the following case:
void foo(A) {}
void main() {
foo(B());
}
You get slicing, because the parameter is taken by value. Which requires a copy.
Exception handlers are not like function calls; C++ will not choose the closest match. It will choose the first valid match. And since B is an A, it therefore matches catch(A).
Again, if you need some kind of quote (though I don't know why; any basic C++ book that describes exception handling will tell you this):
The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.
Note that they even give an example that is exactly your example.
And I am aware that the exceptions should be handled by const reference.
And this is why you take exceptions by reference.