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.
Related
In my program, I am trying to use the assignment operator= to assign an object of my class. I am specifically trying to call the assignment operator instead of an implicit constructor (thus the explicit keyword). When I try to compile, I get a C2440 Compiler Error:
class MyClass {
public:
explicit MyClass(double x = 0.) :
m_x(x) {
}
MyClass& operator = (const double& other) {
m_x = other;
/* do something special here */
return *this;
}
private:
double m_x;
};
int main()
{
MyClass my_class = 2.; // C2440
return 0;
}
I guess that the compiler fails trying to call the constructor implicitly (because of explicit). Does anyone have a fix?
MyClass my_class = 2.; is more or less equivalent to MyClass my_class(2.);, but, you marked the constructor as explicit, which prevents C++ from doing that automatically.
So, in the way you've written your code, you cannot really do what you want. You could explicitly call the constructor using:
MyClass my_class(2.); // Explcitly call your constructor
Or, as Ted Lyngmo mentioned in the comments, you can do:
MyClass my_class; // Call your constructor with default argument of 0
my_class = 2.; // then call your assignment operator
(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.
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.
I was trying the following program :
#include <iostream>
using namespace std;
class Type{
int i;
public:
Type() {cout << "type constructor "<<endl;}
Type (const Type &) { cout << "type copy constructor called" << endl;}
};
class MyClass {
Type variable;
public:
MyClass(Type a) {
cout << "inside MyClass constructor "<<endl;
variable = a;
}
};
void fun (Type){
return;
}
int main (){
Type t;
cout <<"t created"<<endl;
MyClass tmp = MyClass(t);
cout<<"calling fun"<<endl;
fun(t);
}
The output of this is :
type constructor
t created
type copy constructor called
type constructor
inside MyClass constructor
calling fun
type copy constructor called
I am wondering why default constructor is called when I pass it to MyClass constructor and why copy constructor is called when I pass it to fun()?
BTW same happens when I use initializer list.
I am wondering why default constructor is called when I pass it to MyClass constructor
It has nothing to do with passing argument here. As a member variable, variable will be default constructed at first.
class MyClass {
Type variable;
public:
MyClass(Type a) { // variable will be default constructed at first, since it's not initialized via member initializer list
cout << "inside MyClass constructor "<<endl;
variable = a; // then variable is assgined via assignment operator
}
};
You can specify how variable would be initialized by member intializer list, like
class MyClass {
Type variable;
public:
MyClass(Type a) : variable(a) { // variable will be direct initialized via copy constructor
cout << "inside MyClass constructor "<<endl;
// variable = a; // no need for assignment
}
};
The default constructor won't be called for this case.
Copy constructor is invoked for both the parameters (the one for MyClass constructor and the one for fun) and the logs you posted report that.
In fact, you have two times the following line:
type copy constructor called
Default constructor is invoked for data member variable, for it is not explicitly initialized.
The same happens if you use an initializer list like this:
MyClass(Type a): variable{} {
//...
}
Actually, variable is default initialized if you don't have any initializer list, so there is no reason to expect a different log.
I have a class that has a few int and a const int member with a constructor defined.
class SomeContainer
{
public:
SomeContainer():
member1(0),
member2(staticMethod())
{}
private:
static int staticMethod();
int member1;
const int member2;
}
I need to create an assignment operator since I use this class in another class MainClass and code
MainClass* p1;
MainClass* p2
{
//...
*p1 = *p2 // fails since SomeContainer doesn't have copy assignment operator
}
Should this code be enough or am I missing anything?
{
SomeContainer(const SomeContainer& other): // copy ctor
member1(other.member1),
member2(other.member2)
{}
SomeContainer& operator=(const SomeContainer& other) // assignment operator
{
member1 = other.member1;
}
}
what about move ctor and move assignment? Should I need to implement those as well?
First of all if p1 and p2 are pointers then you can just assign them.
In case move constructor is not present then copy constructor will be used instead.
It remains for me hard to understand what is the logical meaning of allowing assignment on something that has constant non-static parts.
What you have written is sufficient.
When no move constructor exists then the copy constructor will be used instead, and there's really no purpose in move semantics here.
Just remove const from that member if you really need assignment