Implementation supplied copy constructor and assignment operator - c++

I have a small confusion regarding the situations where the implementation (compiler) will not supply the copy constructor and the copy assignment operator.
When we declare the copy ctor and/or copy assignment operator in our class.
Some says when we derive from a class which has a private copy ctor and/or copy assignment operator.
I am a little confused about the second situation, is the second situation is precisely.
a) The implementation will not declare them for you, so you will get a compile time error.
OR
b) The implementation will declare and define them, but when the compiler defined implementation tries to find the base class' method, we will get a compile time error.
I had an interview yesterday, I said its (b) that is happening but the interviewer disagrees, he says its (a).
I tried to compile the following code in both Microsoft C/C++ 14.00 and gcc 4.4.5
struct A
{
private:
A& operator = ( const A& );
};
struct B : A
{
};
int main()
{
B b1;
B b2;
b1 = b2;
return 0;
}
Microsoft compiler output
ctor01.cpp(9) : error C2248: 'A::operator =' : cannot access private member declared in class 'A'
ctor01.cpp(4) : see declaration of 'A::operator ='
ctor01.cpp(2) : see declaration of 'A'
This diagnostic occurred in the compiler generated function 'B &B::operator =(const B &)'
gcc compiler output
Ctor01.cpp: In member function ‘B& B::operator=(const B&)’:
Ctor01.cpp:4: error: ‘A& A::operator=(const A&)’ is private
Ctor01.cpp:8: error: within this context
Ctor01.cpp: In function ‘int main()’:
Ctor01.cpp:15: note: synthesized method ‘B& B::operator=(const B&)’ first required here
So I think, the implementation will declare and define it, but when the compiler defined implementation tries to find the base class method, we will get a compile time error. Correct me if I am wrong.

Regarding the copy constructor, this is what the standard says (12.8/7) :
A program is illformed if the class
for which a copy constructor is
implicitly defined has:
a nonstatic data member of class type (or array thereof) with an
inaccessible or ambiguous copy
constructor, or
a base class with an inaccessible or ambiguous copy
constructor.
Regarding the copy assignment operator (12.8/12) :
A program is illformed if the class
for which a copy assignment operator
is implicitly defined has:
a nonstatic data member of const type, or
a nonstatic data member of reference type, or
a nonstatic data member of class type (or array thereof) with an
inaccessible copy assignment operator,
or
a base class with an inaccessible copy assignment operator.
How the compiler reports the error, or how it actually falls into it, is pretty much irrelevant from my point of view.
However, I do believe that answer (b) is probably more correct : the base class copy assignment is declared, and it's inaccessible. The derived class has an implicitly declared copy assignment which the compiler will try to define if used, thus making the program ill-formed.

A class will have a copy constructor and a copy assignment operator implicitly declared if there is no user declared version of either. This always happens.
Simplistically, the implementation will implicitly define these only if they are actually used. If, when the implementation tries to define them, the implicit definition would be ill-formed (e.g. for copy-assignment the class contains a reference member or const member or for the copy constructor a base or member has private copy constructor) then the program is ill-formed.
A program can still be valid if it contains classes which have implicitly declared copy constructors and copy assignment operators which cannot be implicitly defined so long as it does not cause these to actually be defined by using them or causing them to be used.

Your case (b) is more accurate.
C++03 Standard 12.8p10
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.
And 12.8p12
An implicitly-declared copy assignment operator is implicitly defined when an object of its class type is assigned a value of its class type or a value of a class type derived from its class type. A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:
a nonstatic data member of const type, or
a nonstatic data member of reference type, or
a nonstatic data member of class type (or array thereof) with inaccessible copy assignment operator, or
a base class with an inaccessible copy assignment operator.
The corresponding requirements for implicitly defined copy constructors, default constructors, and destructors have similar wordings.
Specifying that the methods exist even though their definitions will be illegal clarifies some things about overload resolution. For example,
class A {
private:
A& operator=(const A&);
};
class B : public A {
public:
operator int() const;
B& operator=(int);
};
void f(B& b1, const B& b2)
{ b1 = b2; }
is illegal because the implicitly-declared B::operator=(const B&) is the better overload but the implicit definition is ill-formed. Without that declaration, you might think the compiler should implicitly convert b2 to int and then assign that to b1.

I think the distinction between the two depends on the details of your specific implementation (and doesn't make much difference). For what it's worth, Comeau gives this:
"ComeauTest.c", line 7: error: "A &A::operator=(const A &)" (declared at line 4) is
inaccessible
struct B : A
^
detected during implicit generation of "B &B::operator=(const B &)"
at line 16
1 error detected in the compilation of "ComeauTest.c".
So on that compiler, it detects the error "during" the implicit generation of B's assignment operator. In other words, it tries to generate it, and finds that it can't. Whether it detects it as it's writing it out, or by looking at A directly, doesn't really matter.

This is what happens :
struct A
{
private:
A& operator = ( const A& );
};
struct B : A
{
B& operator = ( const B& other )
{
A::operator=( other );
return *this;
}
};
int main()
{
B b1;
B b2;
b1 = b2;
return 0;
}
The default operator= tries to call A::operator=, which is private.

The standard seems to agree with you. Quoting from the current draft:
§12.8/8:
If the class definition does not
explicitly declare a copy constructor
and there is no user-declared move
constructor, a copy constructor is
implicitly declared as defaulted
(8.4).
§12.8/12:
A defaulted copy/move constructor for
a class X is defined as deleted
(8.4.3) if X has: […]
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 […]
So the synthesized copy constructor is declared and defined, but defined as deleted.

Related

C++ primer 5 ed. Virtual destructor and move semantics

In C++ primer 5 ed. it is said:
"The fact that a base class needs a virtual destructor has an important indirect impact on the definition of base and derived classes: If a class defines a destructor—even if it uses = default to use the synthesized version—the compiler will not synthesize a move operator for that class (§13.6.2, p. 537)."
So for more understanding I've tried this:
class A
{
public:
A(){cout << "A::A()\n";}
virtual ~A(){cout << "A::~A()\n";}
A& operator = (const A&) {cout << "A::=\n"; return *this;};
A& operator = (A&&) = default;
};
int main()
{
A a;
A a2;
a2 = std::move(a); // why copy-assignment operator is not called here. Normally a will be "moved" through copy-ctor (moving through working copy-ctor)
std::cout << std::endl;
}
So according to the text above in the book class A has a virtual destructor thus the compiler won't synthesize a move-ctor/assignment operations But in main I've tried to move an object of type class A so normally move here uses copy-assignment instead of move-assignment but copy-assignment is not called here?!
So when a vairtual dtor causes a default operation be not synthesized? Thank you!
Your textbook is right, the compiler won't automatically synthesize a move operator. In the code sample you force the compiler to generate one by setting it to default, this can only fail if the move operator is implicitly deleted. Which is something else than it being implicitly declared.
Criteria for implicit deletion:
A has a non-static data member that is const
A has a non-static data member of a reference type
A has a non-static data member that cannot be move-assigned (has deleted, inaccessible, or ambiguous move assignment operator)
A has direct or virtual base class that cannot be move-assigned (has deleted, inaccessible, or ambiguous move assignment operator)
A has a non-static data member or a direct or virtual base without a move assignment operator that is not trivially copyable
A has a direct or indirect virtual base class
Criteria for implicit declaration:
there are no user-declared copy constructors;
there are no user-declared move constructors;
there are no user-declared copy assignment operators;
there are no user-declared destructors;
the implicitly-declared move assignment operator would not be defined as deleted
source

Using copy assignment in derived class

The cppreference says:
Because the copy assignment operator is always declared for any class, the base class assignment operator is always hidden. If a using-declaration is used to bring in the assignment operator from the base class, and its argument type could be the same as the argument type of the implicit assignment operator of the derived class, the using-declaration is also hidden by the implicit declaration.
From my understanding, the following code should not compile. Because
B::operator=(const B&) is implicitly declared.
both A::operator=(const A&) and using-declaration are hidden.
#include <iostream>
using namespace std;
class A {
public:
A& operator=(const A& A) {
cout << "A::opreator=" << endl;
}
};
class B : A {
public:
using A::operator=;
};
int main() {
A a1;
B b1;
b1 = a1;
}
However, it compiles successfully and prints "A::operator=", why?
From C++11 Standards#12.8 [emphasis added]:
24 Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the corresponding assignment operator of a derived class (13.5.3). A using-declaration(7.3.3) that brings in from a base class an assignment operator with a parameter type that could be that of a copy/move assignment operator for the derived class is not considered an explicit declaration of such an operator and does not suppress the implicit declaration of the derived class operator; the operator introduced by the using-declaration is hidden by the implicitly-declared operator in the derived class.
The implicit declaration of class B assignment operation will be like this:
B& B::operator=(const B&)
The parameter type of using-declaration assignment operator in class B is different from implicitly declared assignment operator. Hence, it suppress the implicit declaration of the derived class B operator.
For understanding on 1 & 2 w.r.t. to the code you have posted:
No, the implicit declaration of assignment operator is suppressed in class B.
No, they will not be hidden.
You can't hide the copy assignment operator of B because both operators you've mentioned take different parameters.
I think the reference you mentioned should be broken into 2 parts that suite your 2 question:
Yes, the copy assignments for base class (A) and derived class(B) are implicitly declared by default. You just overriden the implicit declaration on class A by output a message to stream.
the second part of the reference means that if the instance of class B is assigned to an instance of class A and there is a using-declaration to use class A assignment, then the assignment of class A will be used. Which means, if an instance of class B is assigned to an other instance of class B, the default implicit assignment will be used. Therefore, nothing is hidden due to the difference in argument type and the code will call the using-declaration (a.k.a the base class assignment) => the message is output to stream.
I don't see any conflict in this code with standard.
b1 = a1;
This assignment is done because you used using-declaration of base class.
and also " implicit assignment operator of the derived class" is provided by compiler because if you want to assign two objects of derived class it's possible.

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.

c++ Inheriting private copy constructor: how doesn't this yield a compile time error?

In C++, if we have this class
class Uncopyable{
public:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
and then we have a derived class
class Dervied: private Uncopyable{
};
My question is: why won't this generate a compile time error when the compiler generates the default copy constructor and assignment operators in the derived class ? Won't the generated code try to access base class private members ?
C++11 12.8/7 states "If the class definition does not explicitly declare a copy constructor, one is declared implicitly." so Dervied has an implicitly declared copy constructor. 12.8/11 says:
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.
Specifically, the third bullet applies: Dervied has a direct base class Uncopyable that cannot be copied because overload resolution results in a function that is inaccessible from Dervied::Dervied(const Dervied&). As a result Dervied's implicitly declared copy constructor is declared as deleted, resulting in a compile time error if and only if that copy constructor is called.
why won't this generate a compile time error when the compiler generates the default copy constructor and assignment operators in the derived class ?
Because the compiler generates them only when they are needed by the code being compiled. Write some code using the derived class where the copy constructor and/or assignment operator are involved, and you will see the compile-time error you are looking for.
The private in the inheritance makes them private to Derived, it can still see them, classes that use Derived can't.
The derived class will inherit the private copy constructor but will not need to use it unless you copy an object of derived type, as in this example.
The compiler does not auto-generate constructors/operators unless they are used and no other constructor/operator can be used to do that operation (i.e. a copy operation can be used in some situations where a move operation would suffice). The latter statement results in the following set of rules.
Here are the rules to the auto-generation of certain member functions:
Default constructor (if no other constructor is explicitly declared)
Copy constructor if no move constructor or move assignment operator
is explicitly declared. If a destructor is declared generation of a
copy constructor is deprecated.
Move constructor if no copy
constructor, move assignment operator or destructor is explicitly
declared.
Copy assignment operator if no move constructor or move assignment
operator is explicitly declared. If a destructor is declared
generation of a copy assignment operator is deprecated.
Move assignment operator if no copy constructor, copy assignment operator
or destructor is explicitly declared.
Destructor
The list is taken from this Wikipedia page.
One class cannot call private methods on another class, but it can inherit as much as it is coded too. This code just includes the member functions from Uncopyable in Derived.
Imagine if you wrote a class inheriting from std::vector. You can still erase, insert, push_back and do all those sorts of things. Because these are all public or protected vector member functions, they in turn call implementation specific private functions that do the low level things like manage memory. Your code in this derived class couldn't call those memory management functions directly though. This is used to insure the creators of the vector can change the internal details freely without breaking your use of the class.
If your example is what the code actually looks like, then this it is a common pattern used to make things that cannot be copied. It would make code like the following produce a compiler error:
Derived Foo;
Derived Bar;
Foo = Bar
It would also make the code throw an error on the following:
int GetAnswer(Derived bar)
{ /* Do something with a Derived */ }
Derived Foo;
int answer = GetAnser(Foo);
This example fails because a copy of foo is made and passed as the parameter in the function GetAnswer.
There are many reasons why something might not be copyable. The most common I have experienced is that the object manages some low level resource a single file, an opengl context, an audio output, etc... Imagine if you had a class that managed a log file. If it closed the file in the deconstructor, what happens to the original when a copy is destroyed.
Edit: to pass an Uncopyable class to a function, pass it by reference. The Following function does not make a copy:
int GetAnswer(Derived& bar)
{ /* Do something with a Derived */ }
Derived Foo;
int answer = GetAnser(Foo);
It would also cause a compiler error if all the constructor were private and the class was instantiated. But even if all the member function even constructors were private and the class was never instantiated that would be valid compiling code.
Edit: The reason a class with constructor is that there maybe other way to construct it or it maybe have static member functions, or class functions.
Sometimes factories are used to build object which have no obvious constructor. These might have functions to whatever magic is required to make the umakeable class instance. The most common I have seen is just that there was another constructor that was public, but not in an obvious place. I have also seen factories as friend classes to the unconstructable class so they could call the constructors and I have seen code manually twiddle bits of memory and cast pointers to the memory it to an instance of a class. All of these patterns are used to insure that a class is correctly created beyond just the guarantees C++ supplies.
A more common pattern I have seen is static member functions in classes.
class uncreateable
{
uncreateable() {}
public:
static int GetImportantAnswer();
};
Looking at this it can be seen that not only do I not need to create a instance of the class to call GetImportantAnswer() but I couldn't create an instance if I wanted. I could call this code using the following:
int answer;
answer = uncreateable::GetImportantAnswer();
Edit: Spelling and grammar
Well, actually this program does not compile with g++:
#include <iostream>
using namespace std;
class Uncopyable{
public:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&) {cout<<"in parent copy constructor";}
Uncopyable& operator=(const Uncopyable&) { cout << "in parent assignment operator";}
};
class Derived: private Uncopyable{
};
int main() {
Derived a;
Derived b = a;
}
compiler output:
$ g++ 23183322.cpp
23183322.cpp:10:88: warning: control reaches end of non-void function [-Wreturn-type]
Uncopyable& operator=(const Uncopyable&) { cout << "in parent assignment operator";}
^
23183322.cpp:13:7: error: base class 'Uncopyable' has private copy constructor
class Derived: private Uncopyable{
^
23183322.cpp:9:5: note: declared private here
Uncopyable(const Uncopyable&) {cout<<"in parent copy constructor";}
^
23183322.cpp:19:15: note: implicit copy constructor for 'Derived' first required here
Derived b = a;
^
1 warning and 1 error generated.

Do derived classes indirectly inherit base's assignment operator?

I'm trying to understand this behaviour but it seems I don't. Please see this code:
#include <iostream>
using namespace std;
class Base
{
public:
void operator=(const Base& rf)
{
cout << "base operator=" << endl;
this->y = rf.y;
}
int y;
Base() : y(100) { }
};
class Derived : public Base
{
public:
int x;
Derived() : x(100) { }
};
int main()
{
Derived test;
Derived test2;
test2.x = 0;
test2.y = 0;
test.operator=(test2); // operator auto-generated for derived class but...
cout << test.x << endl << test.y << endl;
cin.ignore();
return 0;
}
PROGRAM OUTPUT:
> base operator=
> 0
> 0
Now where I'm confused is:
The rule says that a derived class never inherits the assigment operator, instead it creates its own operator= however in this example base's operator= gets invoked on the derived class.
Second I was able to explicitly invoke an assigment operator on a derived class, which isn't in turn explicitly defined in the derived class.
Now if I understand it correctly, this means that any user defined base's operator always gets invoked on the derived class?
The generated ones automatically call the base-class assignment operator.
// generated version looks basically like this
Derived& operator=(Derived const& other){
Base::operator=(static_cast<Base const&>(other));
x = other.x;
return *this;
}
The cast is there to avoid an accidential call to a templated Base::operator= like this one:
template<class Other>
Base& operator=(Other const& other); // accepts everything
Or a strange one like this:
// forward-declare 'Derived' outside of 'Base'
Base& operator=(Derived const& other); // accepts derived class (for whatever reason)
Second I was able to explicitly invoke an assigment operator on a derived class, which isn't in turn explicitly defined in the derived class.
The compiler automatically declares an assignment operator if you do not and your class allows it (i.e., no reference members and some other arcane rules) and additionally defines it if you actually use it somewhere.
The compiler-generated assignment operator calls the assignment operator of each subobject. That includes base classes and non-static member variables.
The standard says (section 12.8 [class.copy]):
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor. The implicitly-declared copy assignment operator for a class X will have the form
X& X::operator=(const X&)
if
each direct base class B of X has a copy assignment operator whose parameter is of type const B&,
const volatile B& or 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 assignment operator whose parameter is of type const M&, const volatile M& or M.
Otherwise, the implicitly-declared copy assignment operator will have the form
X& X::operator=(X&)
and
The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy/move assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Let x be either the parameter of the function
or, for the move operator, an xvalue referring to the parameter. Each subobject is assigned in the manner appropriate to its type:
if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);
if the subobject is an array, each element is assigned, in the manner appropriate to the element type;
if the subobject is of scalar type, the built-in assignment operator is used.
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy assignment operator.
That's because the implicitly defined operator = calls the base classes operator =. See the FAQ lite:
I'm creating a derived class; should my assignment operator call my base class's assignment operator?
Yes (if you need to define an assignment operator in the first place).
If you define your own assignment operator, the compiler will not automatically call your base class's assignment operator for you. Unless your base class's assignment operator itself is broken, you should call it explicitly from your derived class's assignment operator (again, assuming you create one in the first place).
However if you do not create your own assignment operator, the one that the compiler creates for you will automatically call your base class's assignment operator.
4 things never get inherited
Constructor
Copy-constructor
Assignment operator
Destructor
Even you have not written the assignment operator your code will be Woking fine.
Whenever you use assignment operator compiler will make sure that assignment operator for each member object and base class get called.