I am confused over the differences between passing objects by reference and by value to functions of a particular class. If I pass objects by value, I know that the default copy constructor makes a member-by-member copy of the the object for use in the given function. However, if I am passing objects as a const reference for a class that requires deep copy, is the copy constructor still called? Say that I had a function
void debug(const MyClass& object1);
Would passing object1 call the copy constructor? Or is the object passed into the function directly without having a copy made? One more question - If I have a class called Fraction-
Fraction A(1,2); // 1 is this numerator, 2 the denominator
A = Fraction(2,3);
Does the aforementioned line call the default constructor to make a temporary object Fraction(2,3) and then the assignment operator?
Thanks.
Would passing object1 call the copy constructor?
No, it will not call the copy constructor since passed by reference
No copy is made in this case
A = Fraction(2,3);
Yes, it will call the constructor with two parameters (or default constructor if both parameters have default values), then call the copy assignment operator.
You can see the output from code below:
#include <iostream>
using namespace std;
class Fraction
{
public:
int denom;
int nominator;
Fraction(int d , int n ):denom(d), nominator(n)
{
cout << "call non-copy constructor" <<endl;
}
Fraction(const Fraction& rhs)
{
cout << "call copy constructor" <<endl;
denom = rhs.denom;
nominator = rhs.nominator;
}
const Fraction& operator=(const Fraction& rhs)
{
cout << "call copy assignment operator" << endl;
if (this == &rhs)
{
return *this;
}
denom = rhs.denom;
nominator = rhs.nominator;
return *this;
}
};
void debug(const Fraction& obj)
{
cout << "this is debug: pass by reference " <<endl;
}
void debugPassByValue(Fraction obj)
{
cout << "this is debug: pass by value" <<endl;
}
int main()
{
Fraction A(1,2);
cout << "--------------" <<endl;
debug(A);
cout << "--------------" <<endl;
A = Fraction(2,3);
cout << "--------------" <<endl;
debugPassByValue(A);
cout << "--------------" <<endl;
cin.get();
return 0;
}
You will see the following output:
call non-copy constructor //Fraction A(1,2);
--------------
this is debug: pass by reference //debug(A);
--------------
call non-copy constructor //A = Fraction(2,3);---> construct temporary object
call copy assignment operator //A = Fraction(2,3);
--------------
call copy constructor //debugPassByValue(A);
this is debug: pass by value
--------------
Now you will have a clearer view of what are called.
In the following we will consider [x] to mean that x is optional.
I am confused over the differences between passing objects by reference and by value to functions of a particular class.
When you pass an object by value, the program must create the local object of the function therefore it calls the copy constructor of the class to create this object. When you pass by reference (and seemingly by pointer) the variable object1 inside the function is just an alias of the object you passed to the function; therefore if you edit the one inside the function, the edits will be applied to the outside object as well.
Does the aforementioned line call the default constructor to make a temporary object Fraction(2,3) and then the assignment operator?
It's the assignment operator. Considering A to be an already declared variable of type X it will be called X Fraction::operator=([const] Fraction[&]) or any compatible type.
Notice: when declaring Fraction x = Fraction(2, 3) it won't be used the operator= as you may expect, the corresponding constructor will be called instead (in this case Fraction::Fraction([const] Fraction[&])).
Indeed in the case of debug no copy is made.
In the second case, I'm not quite sure I understand your question. This line:
A = Fraction(2,3);
Should use Fraction's assignment operator. A already exists, so it uses the assignment operator on instance A to assign it Fraction(2,3) which is a temporary object.
Related
I would like to ask a question about references and pointers in C++.
I am a beginner in C++ so I apologise for if the answer is trivial.
I have written the following code as part of a tutorial.
#include <iostream>
using namespace std;
class Deep {
private:
int *data;
public:
void set_data_value(int d) {*data = d;}
int get_data_value () {return *data;}
// Constructor
Deep (int d);
// Copy constructor
Deep (const Deep &source);
// Destructor
~Deep();
};
Deep::Deep(int d) {
data = new int;
*data = d;
}
Deep::Deep (const Deep &source)
: Deep (*source.data){ // main body of the constructor (delegation comes before the body)
cout << "Copy Constructor - deep copy" << endl;
}
Deep::~Deep() {
delete data;
cout << "Destructor deleting data" << endl;
}
void display_deep (Deep s) {
cout << s.get_data_value() << endl;
}
int main () {
Deep obj1 {100};
display_deep (obj1);
Deep obj2{obj1};
obj2.set_data_value(1000);
cout << endl;
return 0;
}
This code works. I will explain what I have done:
I defined a class named Deep to practice a deep copy. The pointer named data is private and I've included (and later defined) the function prototypes set_data_value and get_data_value.
set_data_value takes in an integer d, dereferences data and assigns the value d to it.
get_data_value simply returns the dereferenced value of data.
In the public domain also there is a constructor that accepts one integer d, a copy constructor which keeps the object constant and takes in a reference &source alongside a destructor.
Inside the copy constructor, I use a delegation constructor to improve the flow of the code.
However, if we observe the copy constructor
Deep::Deep (const Deep &source)
: Deep (*source.data){ // main body of the constructor (delegation comes before the body)
cout << "Copy Constructor - deep copy" << endl;
}
we know that this is run upon the pass-by-value nature of void display_deep (Deep s), so source is a reference to our s passed in. We then point to source and somehow obtain the value of data, which is then passed to the constructor.
How does this work? Does *source.data work as I described or does the compiler take a different route?
We then point to source and
There is no pointing to anything. In this line:
: Deep (*source.data)
You are just accessing the data inside source. Then you are dereferencing it. Just like you dereference *data to get the value inside it.
I am very new to C++ and I don't understand why the copy constructor was called in the following code:
#include <iostream>
using namespace std;
class Line
{
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void )
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main( )
{
Line line(10);
display(line);
return 0;
}
And when it runs:
Normal constructor allocating ptr
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Freeing memory!
Why does it construct an other Line object after the first one with the simple constructor?
Thanks!
because you are passing Line as value
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
You should pass it as constant reference, which is faster (and display shoud be a constant method so constant objects can call it).
void display(const Line &obj) const
{
cout << "Length of line : " << obj.getLength() <<endl;
}
(provided that you change to int getLength( void ) const;)
And in your case, think of redefining assignment operator
Line &operator=(const Line &other);
or affecting a line in another will copy pointer data and will crash on your second object deletion since memory will be freed twice.
If you want to make sure that default copy constructor / assignment operator cannot be called, just declare them in your private part:
private:
Line &operator=(const Line &other);
Line(const Line &other);
code trying to use them won't compile.
Your display function takes a Line by value - meaning the function gets its own copy. If you don't want that, pass by (const) reference or pointer instead.
The answer is here:
void display(Line obj) { ...
The argument of the function obj is passed by value.
So when the function is called a copy of the argument passed by the caller function is done.
In order to give you a trivial explanation, imagine:
function:main (caller) ->
make a copy of line ->
call the function display (callee) which is going to use the copy made by caller.
That policy is used in various case, for example:
To be sure that the callee function will does any effect (side-effect) on the variables of the caller.
When the callee function will perform a copy of the object, so you can avoid to make a copy inside the body function.
Because passing an argument by value will perform a copy of the argument itself, it is preferable using argument passed by reference.
This is an example:
void display(Line& obj) { ...
In that case it will not performed a copy of the object but the argument obj will be a reference (like a pointer) to the argument passed by the caller function.
In conclusion, passing by reference allows to callee function side effect, in other words the callee function can modify variables "owned" by caller function.
Copy constructors are called in following cases:
(a) when a function returns an object of that
class by value
(b) when the object of that class is passed by
value as an argument to a function
(c) when you construct an object based on another
object of the same class
(d) When compiler generates a temporary object and is initialized with a class object.
And in your code you are passing the object of that clas by value as an argument to a function
Hope this Helps
I Have just created a class with an integer variable and a pointer variable. After creating its object , I passed it to a function. Even after returning the function the program is not throwing the exception
#include"iostream"
using namespace std;
class A
{
public :
int i;
char *c;
void show();
};
void func(A obj);
int main()
{
A a;
a.i = 10;
a.c = "string";
cout << " Before Fun " << endl;
a.show();
cout << " Going To Call func " << endl;
func(a);
cout << " After func " << endl;
a.show();
return 0;
}
void A::show()
{
cout << " The valuses in Object are " << i << '\t' << c << endl;
}
void func(A aa)
{
cout << " The valuses in Object are " << aa.i << '\t' << aa.c << endl;
}
In The Func I am passing the object a (from main) and it would get copied in aa (stack of func). so after returning from the func if i call show ( the pointer c would be null of a), It would give me exception
But it is not happening . please help me to prove the requirement of copy constructor
Hide the copy constructor. That will cause a compilation error everywhere it is called implicitly.
class A
{
public :
int i;
char *c;
private:
A(const A& _other);
};
If no copy constructor is declared for an object, one is implicitly defined. This copy constructor copies each element of the object.
In your example, the call to func(a) will call this copy constructor, and so aa will be a copy of a (aa.i will be 10 and aa.c will point to the first element of "string").
If you are using C++11 you can do the following to remove the copy constructor
class A
{
public :
int i;
char *c;
void operator=(const A& _other) = delete;
A(const A& _other) = delete;
};
or even better:
class A : public NonCopyable // perhaps std:: or if you prefer boost, boost::
{
public :
int i;
char *c;
};
http://en.wikipedia.org/wiki/C++11#Explicitly_defaulted_and_deleted_special_member_functions
When you make a class, a null constructor and copy constructor exist implicitly.
So that is why it does not throw an exception.
However, if you define ANY constructor, you will then need to define others otherwise the rest of the constructors will be overwritten.
For example, you define a null constructor only. Then it will throw an exception. Because the implicitly defined copy constructor will be overridden.
This is one way of proving the need of a copy constructor.
An implicit copy constructor does exist if you do not define one explicitly. It is called in your func() function. A object is copied and assigned a value for its member i.
Result will be: that you do get with show() the value for i that you had before when calling func. This is with no surprise because you are not doing any assignment to members of A inside A.
Implicit copy constructor by the compiler provide member-wise copy. This is what you may need in most cases.
When is default constructor not sufficient ? you have pointer like members, and need a deep-copy of it. You don't want to copy the pointer (what copy constructor would do), but rather to have the object pointed to copied. But why do you need deep copy ? You don't want to copy the pointer (which is owned by any instance of the class), and end up calling twice destructor on the same pointer. From the second call to delete on this pointer, heap corruption ensues. You may also need copy constructor made explicit for shared_pointers.
Note that, for performance reasons, it is best pass object by const reference than by value.
In your case the copy constructor provided by compiler is present.
Modify your code and write a copy constructor as:
//Default and copy constructor
A()
{
i = 0;
c = NULL;
}
A(const A& _other)
{
cout<<"In copy cons"<<endl;
}
When you will modify the code as per above when func gets called then your own copy constructor gets called in this case you will get the junk values(can not predict)
And if you modify your copy constructor code as
A(const A& _other)
{
cout<<"In copy cons"<<endl;
i = _other.i;
c = new char [(strlen(_other.c) +1)];
strcpy(c,_other.c);
}
Now you can see the differnce in both outputs and the use of Copy constructor how and where it's used.
I'm having difficulty wrapping my mind around the following (specifically, scenario b):
(Assume I have defined an assignment operator, addition operator, and copy constructor just to output the fact that they are being called)
scenario a:
Simple a;
Simple b;
Simple c = a + b;
The output is as follows:
Simple constructor called
Simple constructor called
Simple add operator call
Simple constructor called
copy constructor called
-- This is all fine and dandy
scenario b (the behavior that I cannot understand):
Simple d;
Simple e;
Simple f;
f = d + e;
Simple constructor called
Simple constructor called
Simple constructor called
Simple add operator called
Simple constructor called
copy constructor called
assignment operator called
The question that I have is that in scenario b, why is the copy constructor called right before the assignment operator is? To my understanding, a copy constructor will only be called on an uninitialized object. However, in this scenario, the object f has been initialized in the line preceding the addition.
An explanation would be greatly appreciated.
Apologies for not posting the source code right away (and for the lack of indentation - I am having problems copying to the textarea). Here it is in all of it's simplicity.
I am using Visual Studio 2005. Unfortunately, I am not that familiar with the workings of it yet, hence I cannot specify the optimization parameters that are being passed to the compiler.
class Simple
{
public:
Simple(void);
Simple operator +(const Simple& z_Simple) const;
Simple& operator =(const Simple& z_Simple);
Simple(const Simple& z_Copy);
int m_Width;
int m_Height;
public:
~Simple(void);
};
#include "Simple.h"
#include <iostream>
using std::cout;
using std::endl;
Simple::Simple(void)
{
this->m_Height = 0;
this->m_Width = 0;
cout << "Simple constructor called" << endl;
}
Simple::Simple(const Simple& z_Copy)
{
cout << "copy constructor called" << endl;
this->m_Height = z_Copy.m_Height;
this->m_Width = z_Copy.m_Width;
}
Simple& Simple::operator =(const Simple &z_Simple)
{
cout << "assignment operator called" << endl;
this->m_Height = z_Simple.m_Height;
this->m_Width = z_Simple.m_Width;
return *this;
}
Simple Simple::operator +(const Simple &z_Simple) const
{
cout << "Simple add operator called" << endl;
int y_Height = this->m_Height + z_Simple.m_Height;
int y_Width = this->m_Width + z_Simple.m_Width;
Simple y_Ret;
y_Ret.m_Height = y_Height;
y_Ret.m_Width = y_Width;
return y_Ret;
}
Simple::~Simple(void)
{
cout << "destructor called" << endl;
}
Certainly Nemo's explanation is the one that my novice C++ mind can grasp :)
After changing the optimization level to /O2, I can see the output of scenario b as follows (and what I would have expected)
Simple constructor called
Simple constructor called
Simple constructor called
Simple add operator called
Simple constructor called
assignment operator called
Thank you all for your suggestions.
Your + operator returns a object by value, which might result in call to copy constructor if the compiler did not elide it.
Simple Simple::operator +(const Simple &z_Simple) const
{
//......
Simple y_Ret;
//......
return y_Ret;
}
Code:
Simple d;
Simple e;
Simple f;
f = d + e;
Here is a step by step analysis:
Simple constructor called ---> creation of `d`
Simple constructor called ---> creation of `e`
Simple constructor called ---> creation of `f`
Simple add operator called ---> Inside Addition operator
Simple constructor called ---> creation of local `y_Ret`
copy constructor called ---> `y_Ret` returned by value
assignment operator called ---> Result returned by `+` used for `=`
I get a compile error with the following code:
main.cpp: In function âint main()â:
main.cpp:38: error: no matching function for call to âComplex::Complex(Complex)â
main.cpp:22: note: candidates are: Complex::Complex(Complex&)
main.cpp:15: note: Complex::Complex(double, double)
But when I change the argument type of the copy constructor to const Complex&, it works.
I was thinking that the default constructor will be called with 2 Complex::Complex(2.0, 0.0) and then the copy constructor will be called to create a with a copy of Complex(2.0. 0). Isn't it correct ?
#include <iostream>
using namespace std;
class Complex {
double re;
double im;
public:
Complex(double re=0, double im=0);
Complex(Complex& c);
~Complex() {};
void print();
};
Complex::Complex(double re, double im)
{
cout << "Constructor called with " << re << " " << im << endl;
this->re = re;
this->im = im;
}
Complex::Complex(Complex &c)
{
cout << "Copy constructor called " << endl;
re = c.re;
im = c.im;
}
void Complex::print()
{
cout << "real = " << re << endl;
cout << "imaginary = " << im << endl;
}
int main()
{
Complex a = 2;
a.print();
Complex b = a;
b.print();
}
When you write
Complex a = 2;
the compiler will not directly call the Complex constructor using 0 as default argument to build a but instead it will consider if it can "convert" 2 to a Complex.
To do the conversion it will find your Complex(re,im) version and could use that thanks to the default value and to the fact you didn't declare your constructor explicit, but then it will have to find a way transfer this value to a.
The tool for this "transfer" could be a copy constructor. However the complex value that can be built with Complex(re,im) is a temporary, and for some questionable reasons in C++ you are not allowed to pass a temporary as a non-const reference to a function.
So your copy constructor cannot be used with the temporary and the compiler is stuck as there are no ways to initialize a using 2.
If you declare your copy constructor instead accepting a const reference then the temporary can be passed to your copy constructor to initialize a and so everything works as you expect.
Directly initializing a could have been done using the syntax Complex a(2), that in this case doesn't need to use the copy constructor.
Note also that as strange it may be when you use the syntax Complex a = ... the compiler must check if it's legal to use a copy constructor, but once that legality has been checked it is allowed to not call it and use a direct initialization instead. In other words even if you need to declare your copy constructor accepting a const reference to be able to compile still the compiler may actually skip that part and directly build a without calling the copy constructor (even if the copy constructor - as in your case - has side effects). This apparently crazy rule has been added to be able to allow some optimizations in the generated code.
Copy constructors in C++ require the const part of the argument in order to take a const parameter, as you discovered. Otherwise you didn't create a copy constructor that can take a const argument, you created a copy constructor that takes a non-const Complex& as an argument.
You always create a copy construct with & so you don't have to copy the whole object for the function to use it. Creating an object copy takes time, referencing it is much more efficient.
In any case, it is required to preceed your object parameter with const so that the copy constructor is guaranteed not to change the input object. For instance:
Complex::Complex(const Complex &c)
{
cout << "Copy constructor called " << endl;
re = c.re;
im = c.im;
c.im = 'something'; // This would not work
}
Regards,
Dennis M.
The problem with this code is that your copy constructor is defined with this signature:
Complex::Complex(Complex &c)
This takes a non-const reference as a parameter, which probably isn't what you want. This would mean, for example, that if you try to copy a Complex object with the copy constructor, you'd be allowed to modify the original object!
To fix this, change your code to take the Complex by const reference:
Complex::Complex(const Complex &c)
More generally, copy constructors and assignment operators should always take in their arguments by const reference unless you have a very strong reason to think otherwise.
There are a few other things in your code I should probably point out. For starters, in this case, your copy constructor isn't necessary because it just does a straight copy of all the fields. There's a rule of thumb called the "rule of three" that says that you should only have a copy constructor if you have a destructor (and then you should also have an assignment operator). Otherwise, the default functions provided by the compiler should probably be sufficient for what you're doing.
Also, there's no reason to write your own Complex class, unless you absolutely must. The <complex> header defines complex<T> as a library class.