Object as argument desctructor called but not constructor? - c++

(I come from C world and I am a beginner in C++, so simply answer the question)
In c++, argument are passed by value. So I try the following code to understand how it works.
#include <iostream>
using namespace std;
class MyClass {
int a;
public:
MyClass() {
a = 0;
cout<<"Default Constructor call\n"; }
MyClass(int x) {
a = x;
cout<<"Constructor call\n"; }
~MyClass() {
cout<<"Destructor call\n"; }
};
void myfoo(MyClass arg) {}
int main() {
cout<<"Obj declaration\n";
MyClass obj(10);
cout<<"Function call\n";
myfoo(obj);
cout<<"End of main\n";
}
The destructor is called at the end of the function and the constructor is not called at the beginning because there is no constructor MyClass(MyClass& xxx). So, how the object arg is constructed in the function ? A simple memory copy ? Is it enough or is it better to always have a constructor MyClass(MyClass& xxx)

and the constructor is not called at the beginning
Not quite correct. The copy constructor is called, which is implicitly defined by the compiler. You can define one yourself:
MyClass(const MyClass& other) { cout << "Copy Constructor call\n"; }
The implicit copy constructor copies each member using its copy constructor. If any of the members cannot be copied, the copy constructor is implicitly deleted.
One can explicitly disable the copy constructor. In pre C++11 days, the idiom was to declare it private. In modern C++, the delete keyword is used:
MyClass(const MyClass& other) = delete;
If you do this, the code won't compile.

because there is no constructor MyClass(MyClass& xxx).
This is not correct, there is a copy constructor with the signature MyClass(const MyClass&) which is generated by the compiler for you. You can provide your own implementation and write something to the standard output to see that.
MyClass(const MyClass& other) : a(other.a) {
cout<<"Copy constructor call\n";
}
Note that the question when the compiler generates special member functions for you is a bit involved. Maybe too much at the very beginning, but at some point you will have to know. A good overview is the table in this answer.

Related

Why this move constructor is not called wtih rvalue temporary? [duplicate]

class MyClass
{
public:
~MyClass() {}
MyClass():x(0), y(0){} //default constructor
MyClass(int X, int Y):x(X), y(Y){} //user-defined constructor
MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){} //copy constructor
private:
int x; int y;
};
int main()
{
MyClass MyObj(MyClass(1, 2)); //user-defined constructor was called.
MyClass MyObj2(MyObj); //copy constructor was called.
}
In the first case, when MyClass(1, 2) calls the user-defined constructor and returns an object, I was expecting MyObj to call the copy constructor. Why it doesn't need to call the copy constructor for the second instance of MyClass?
Whenever a temporary object is created for the sole purpose of being copied and subsequently destroyed, the compiler is allowed to remove the temporary object entirely and construct the result directly in the recipient (i.e. directly in the object that is supposed to receive the copy). In your case
MyClass MyObj(MyClass(1, 2));
can be transformed into
MyClass MyObj(1, 2);
even if the copy constructor has side-effects.
This process is called elision of copy operation. It is described in 12.8/15 in the language standard.
The copy constructor may be elided in such a case.
Likewise with MyClass MyObj = MyClass( 1, 2 );.
And with
std::string str = "hello";
Such code has an implicit constructor call to convert the char* to a std::string.
std::string str = std::string( "hello" ); // same, written more verbosely
Without copy elision, the "easy" string initialization by assignment syntax would incur an additional deep copy. And that syntax is 99% equivalent to what you have.
Apart from what Potatoswatter and Andrey T. has said, note that you can coax most compilers not to elide constructors. GCC typically provides you with -fno-elide-constructors and MSVC with /Od which should give you the desired output. Here's some code:
#include <iostream>
#define LOG() std::cout << __PRETTY_FUNCTION__ << std::endl // change to __FUNCSIG__ on MSVC > 2003
class MyClass
{
public:
~MyClass() { LOG(); }
MyClass():x(0), y(0){LOG(); } //default constructor
MyClass(int X, int Y):x(X), y(Y){LOG(); } //user-defined constructor
MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){LOG(); } //copy constructor
private:
int x; int y;
};
int main()
{
MyClass MyObj(MyClass(1, 2)); //User-defined constructor was called.
MyClass MyObj2(MyObj); //Copy constructor was called.
}
Compiled with GCC 4.5.0 on MingW32:
g++ -Wall -pedantic -ansi -pedantic tmp.cpp -o tmp -fno-elide-constructors
Output:
$ tmp.exe
MyClass::MyClass(int, int)
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::MyClass(const MyClass&)
MyClass::~MyClass()
MyClass::~MyClass()
What makes you think it's not invoked? Try this [Edit: changing code to use private copy ctor, since availability has to be checked even if use of the copy ctor is elided]:
class MyClass
{
public:
~MyClass() {}
MyClass():x(0), y(0){} //default constructor
MyClass(int X, int Y):x(X), y(Y){} //user-defined constructor
private:
MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){} //copy constructor
int x; int y;
};
int main()
{
MyClass MyObj(MyClass(1, 2)); //User-defined constructor was called.
MyClass MyObj2(MyObj); //Copy constructor was called.
}
Attempting to compile this gives errors for both lines in main:
myclass.cpp(17) : error C2248: 'MyClass::MyClass' : cannot access private member
declared in class 'MyClass'
myclass.cpp(11) : see declaration of 'MyClass::MyClass'
myclass.cpp(4) : see declaration of 'MyClass'
myclass.cpp(18) : error C2248: 'MyClass::MyClass' : cannot access private member
declared in class 'MyClass'
myclass.cpp(11) : see declaration of 'MyClass::MyClass'
myclass.cpp(4) : see declaration of 'MyClass'
Conceptually, the copy ctor is used in both cases, and the compiler is obliged to check that it's accessible. In the first case, however, the compiler is free to elide actual use of the copy ctor, as long as it would be able to use it.

Factory requires only declaration of copy ctor without implementation

I'm experiencing behavior which I don't understand in a copy constructor of derived class.
class A {
A(const A&);
public:
A() = default;
};
class B : public A {
friend class Factory;
B(const int v) : A(), m_test_val(v) {}
public:
int m_test_val;
B(const B&); // no implementation, just declaration
};
class Factory {
public:
static B create(const int v) {
return B(v);
}
};
int main() {
B b = Factory::create(2);
std::cout << b.m_test_val << '\n';
return 0;
}
The behavior I don't understand is a matter of a working copy constructor B::B(const B&); which, however, does not have any implementation.
When I use B::B(const B&) = default; instead, I get an error saying I'm using deleted function (implicitly deleted because of ill-formation) in the return statement of the Factory::create() function (The A::A(const A&) is private and without implementation on purpose).
And of course, when I use B::B(const B&) = delete;, compiler tells me I use a deleted function.
How is it possible that the copy constructor works with no implementation just with declaration?
Note: The example code is based on a much larger code that behaves the same way, hopefully I didn't leave something out.
The actual copy is elided by the compiler, which is allowed since the copy constructor is accessible. The compiler is of course under no obligation to elide this copy and if it didn't I would expect a linker error not finding the implementation of the copy constructor.

When both move and copy constructor is present, which one will be called?

Below is class A which is full of different type of constructor.
If i comment the move constructor, then the copy constructor is called twice : once for passing an object to function fun by value and other by returning from the same function.
Code Snippet
class A {
int x;
public :
A() {
cout<<"Default Constructor\n";
}
A(A&& a) : x(a.x){
cout<<"Move Constructor\n";
a.x=0;
}
A(const A& a){
x=a.x;
cout<<"Copy Constructor\n";
}
A fun(A a){
return a;
}
};
int main() {
A a;
A b;
A c;
c=a.fun(b);
}
OUTPUT :
Default Constructor
Default Constructor
Default Constructor
Copy Constructor
Move Constructor
However, if the move constructor is present, it is called rather than copy constructor. Can anyone eloborate this with a good example, so that i will be clear on this concept.
I would appreciate your help.Thanks.
The standard allows a special case for the case where the expression in the return statement is an automatic duration variable. In this case, the constructor overloads are picked as if the expression in the return was an rvalue.
To be more precise, if the expression in the return statement was an automatic duration variable which was eligible for copy elision, or would be if you ignored the fact that it was a function argument, then, the compiler is required to treat it as an rvalue for the purpose of overload resolution. Note that in C++11, the return statement's expression needs to have the cv-unqualified type as the functions return type. This has been relaxed somewhat in C++14.
For example, in C++11, the following code calls the copy constructor of A, instead of the move constructor:
class A
{
};
class B
{
public:
B(A a) : a(std::move(a)){}
A a;
};
B f(A a)
{
return a;///When this is implicitly converted to `B` by calling the constructor `B(a)`, the copy constructor will be invoked in C++11. This behaviour has been fixed in C++14.
}
in the function A fun(A a) the passed in "copy" of A is basically a temporary variable. If there is no move constructor then the return value is a copy (i.e. copy constructor).
If there is a move constructor then the compiler can perform the more efficient "move" systematics on the temp variable "A a" instead.

Construction and initialization list : what the compiler do?

I have some questions about constructors in C++. For each question (from (1) to (4)) I would like to know if the behaviour is perfectly defined regarding to the standard.
A) The first one is about initialization of members :
class Class
{
public:
Class()
: _x(0)
, _y(_x)
, _z(_y) // <- (1) Can I initialize a member with other members ?
{
;
}
protected:
int _x;
int _y;
int _z;
};
B) What are the functions added to each class by the compiler ?
template<typename T> class Class
{
public:
template<typename T0>
Class(const Class<T0>& other)
{
std::cout<<"My copy constructor"<<std::endl;
_x = other._x;
}
template<typename T0 = T>
Class (const T0 var = 0)
{
std::cout<<"My normal constructor"<<std::endl;
_x = var;
}
public:
T _x;
};
// (2) Are
// Class(const Class<T>& other)
// AND
// inline Class<T>& operator=(const Class<T>& other)
// the only functions automatically added by the compiler ?
As an example, if I call :
Class<int> a;
Class<int> b(a); // <- Will not write "My copy constructor"
Class<double> c(a); // <- Will write "My copy constructor"
(3) Is this behaviour perfectly normal according to the standard ?
(4) Do I have the guarantee that an empty constructor is not automatically added and that Class<int> x; will write "My normal constructor" ?
Can I initialize a member with other members ?
Yes, as long as those other members have already been initialised; i.e. as long as their declarations come before the member being initialised.
Are [the copy constructor] and [the copy-assignment operator] the only functions automatically added by the compiler ?
It will also implicitly declare a destructor, which will destroy _x using its destructor.
In C++11, a move constructor (Class(Class&&)) and move-assignment operator (Class& operator=(Class&&)) are also implicitly declared, unless you declare a copy or move constructor, or a copy or move assignment operator.
Note that your constructor template is not a copy constructor, and the implicit one will be used instead:
Class<T1> t1;
Class<T1>(t1); // prints nothing
Class<T2>(t1); // prints "My copy constructor" (which is a lie)
Is this behaviour perfectly normal according to the standard ?
Yes, see chapter 12.
Do I have the guarantee that an empty constructor is not automatically added and that Class<int> x; will write "My normal constructor" ?
Yes, a default constructor will only be implicitly declared if you don't declare any constructors at all.

Object Reference and Object pointer

What happens, in case of copy constructor, if I use pointer in the parameter instead of reference variable? for ex.
class MyClass
{
private: int a;
char *str;
public:...
...
MyClass(MyClass *pObj)
{
....
....
}
};
MyClass(MyClass *pObj)
Is not a Copy Constructor, it is an Overloaded Constructor.
The copy constructor takes reference to the same type as argument. Ex:
MyClass(MyClass &)
The compiler generates an copy constructor for your class implicitly if you do not provide your own version.
This copy constructor will be called when compiler needs to generate a copy of an object.
The overloaded constructor said above will only be called when you explicitly call it.
Code Sample:
#include<iostream>
class MyClass
{
private: int a;
char *str;
public:
MyClass(){}
MyClass(MyClass *pObj)
{
std::cout<<"\ninside *";
}
MyClass(MyClass &pObj)
{
std::cout<<"\ninside &";
}
void doSomething(MyClass obj)
{
std::cout<<"\ndoSomething";
}
};
int main()
{
MyClass ob,ob2;
MyClass obj2(&ob); //Explicitly invoke overloaded constructor
ob.doSomething(ob2); //Calls copy constructor to create temp copy of object
return 0;
}
Note the output is:
inside *
inside &
doSomething
By definition, a copy constructor is a constructor with a const reference parameter to the same class.
Any other constructor definition is not a "copy constructor", so it won't be invoked by the compiler when you write something like:
MyClass x = y;
or
MyClass x( y );
Copy constructor is supposed to make a copy from an object and not from pointer.
Why pass by Reference and not by value? Because if you don't do so, the copy constructor will go in creation of the copy of the argument and it will be an endless loop.