I wonder how this code run specifically line 54 (line2 = line1) although there is no overloading for the assignment operator ?
It seems from the output that neither the copy constructor nor the normal constructor were called and surprisingly it gets output as expected 199 199
#include <iostream>
using namespace std;
class Line
{
public:
int getLength();
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr;
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength()
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main()
{
Line line1(199);
Line line2(1);
line2 = line1; // How this is executed ??!
cout << line1.getLength() << " " << line2.getLength() << endl ;
/*display(line1);
display(line2);*/
cin.get();
return 0;
}
What you have there is undefined behavior. You assign line2 = line1 but have no user-defined assignment operator, so you use the default one provided by the compiler. And the default one simply copies all the fields, which in your case includes an int*. That gives you two copies of the same int*, leaks the value that line2 previously pointed to, and eventually double-deletes the one line1 originally pointed to. The second delete of the same pointer, which occurs when line1 goes out of scope at the end of main(), invokes undefined behavior.
If you have a destructor which frees resources, you probably need an assignment operator too. See the Rule of Three: http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
But the best solution is to stop using raw pointers. Use a smart pointer and this problem will not occur in the first place, and you can omit your destructor.
In a situation like this, writing your own copy constructor, assignment operator and destructor should be your last resort, not your first reaction.
Your first reaction should usually be to use some pre-defined class that already handles these chores for you. In this case, changing from a raw pointer to a shared_ptr (for only one possibility) cleans up the code fairly quickly. Using it, the code ends up something like this:
#include <iostream>
#include <memory>
using namespace std;
class Line
{
public:
int getLength();
Line( int len ); // simple constructor
~Line(); // destructor
// copy constructor removed, because the one supplied by the
// compiler will be fine. Likewise the compiler-generated assignment
// operator.
private:
shared_ptr<int> ptr;
};
Line::Line(int len)
{
cout << "Normal constructor allocating ptr" << endl;
// Note the use of make_shared instead of a raw `new`
ptr = make_shared<int>(len);
}
Line::~Line(void)
{
cout << "Freeing memory!" << endl;
// don't need to actually do anything--freeing is automatic
}
int Line::getLength()
{
return *ptr;
}
void display(Line obj)
{
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main()
{
Line line1(199);
Line line2(1);
line2 = line1; // uses compiler-generated assignment operator (which works)
cout << line1.getLength() << " " << line2.getLength() << endl ;
display(line1);
display(line2);
cin.get();
return 0;
}
Depending upon the situation, a unique_ptr might be a better fit than a shared_ptr. In this case, shared_ptr is probably easier to incorporate into the existing code though.
You might also want to read R. Martinho Fernandes' Rule of Zero blog post on this subject.
If no user-defined copy assignment operators are provided for a class type (struct, class, or union), the compiler will always declare one as an inline public member of the class.
This implicitly-declared copy assignment operator has the form T& T::operator=(const T&) if all of the following is true:
Each direct base B of T has a copy assignment operator whose parameters are B or const B& or const volatile B&
Each non-static data member M of T of class type or array of class type has a copy assignment operator whose parameters are M or const M& or const volatile M&
Otherwise the implicitly-declared copy assignment operator is declared as T& T::operator=(T&). (Note that due to these rules, the implicitly-declared copy assignment operator cannot bind to a volatile lvalue argument)
Copied from this article from CPPReference.
Related
This question already has answers here:
Why is the copy constructor called when we pass an object as an argument by value to a method?
(3 answers)
Closed 2 years ago.
I was trying to understand the copy constructor, and read this (https://www.tutorialspoint.com/cplusplus/cpp_copy_constructor.htm) tutorialspoint article about it. However, I'm having trouble understanding when the copy constructor was called in the code below. Doesn't Line line(10) only call the Simple constructor, which then allocates memory for ptr and sets the value at ptr to 10?
Is it because we passed line as an argument to display? So does passing an object as an argument always invoke the copy constructor?
#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;
}
Which prints out:
Normal constructor allocating ptr
Copy constructor allocating ptr.
Length of line : 10
Freeing memory!
Freeing memory!
Doesn't Line line(10) only call the Simple constructor
Yes.
Is it because we passed line as an argument to display?
Yes.
So does passing an object as an argument always invoke the copy constructor?
Not necessarily. For example, some types don't have constructors so copying them won't invoke a constructor. Furthermore, if you pass an rvalue, then move constructor may be invoked instead. Or if the type of the argument is different from the type of the parameter, then a converting constructor or conversion operator may be invoked.
If the parameter is a reference (of same type, so no conversion is involved), then no constructor is invoked.
This question already has answers here:
Why is the copy constructor called when we pass an object as an argument by value to a method?
(3 answers)
Closed 4 years ago.
I have this code. I'm not that proficient in C++, so I'm going to ask several questions:
#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;
cout<<&obj<<endl;
*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() {
int a = 10;
cout<<&a<<endl;
Line line(a);
display(line);
return 0;
}
Here I don't see where we call copy contructor.
Destructor is being called twice. Where is the second object is being created?
Line::Line(const Line &obj) receives address of a as a parameter? I guess not. But why? a by itself is not an instance of Line, so why function accepts that?
What would be the difference between Line::Line(const Line &obj) and Line::Line(const Line obj)
And could you please explain this *ptr = *obj.ptr; . From here i know only lhs, which dereferences ptr (aka sets value of an object). But I didn't get what's in rhs?
I'd appreciate if you explain with less technical terms and more examples, for clarity
Above code outputs this:
0x7fff692196a4
Normal constructor allocating ptr
Copy constructor allocating ptr.
0x7fff69219698
Length of line : 10
Freeing memory!
Freeing memory!
Here for some reason default constructor is called. I don't see any place where we create object without parameter (aka that goes to default constructor)
I don't see any place either! How can you be so sure the default constructor is called? In fact, your class is not constructible using a default constructor because there isn't one. If you try this:
Line l;
It won't compile since there is no default constructor.
Destructor is being called twice. Where is the second object is being created?
It this line:
display(line);
You function receives a value. To have a value both in your main and your display function, you have to copy it somehow. Passing line will copy it from your main to your function.
Line::Line(const Line &obj) receives address of a as a parameter? I guess not. But why? a by itself is not an instance of Line, so why function accepts that?
No. This is a reference. The copy constructor receive a reference from other context to copy it.
What would be the difference between Line::Line(const Line &obj) and Line::Line(const Line obj)
One is a reference, the other is passing by value (a copy, move or other construction). If the copy constructor had to receive a value, how would you copy the value into the copy constructor? The copy constructor must receive a reference.
And could you please explain this *ptr = *obj.ptr; . From here i know only lhs, which dereferences ptr (aka sets value of an object). But I didn't get what's in rhs?
I don't know what you mean by rhs and lhs, is not in the code you posted. But indeed, *ptr = *obj.ptr will set the value from the integer pointed by obj.ptr into the variable pointed by this->ptr.
I recommend getting a good C++ book and follow a tutorial that will teach you the basics.
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 the following code to test out my understanding of basic pointers in C++:
// Integer.cpp
#include "Integer.h"
Integer::Integer()
{
value = new int;
*value = 0;
}
Integer::Integer( int intVal )
{
value = new int;
*value = intVal;
}
Integer::~Integer()
{
delete value;
}
Integer::Integer(const Integer &rhInt)
{
value = new int;
*value = *rhInt.value;
}
int Integer::getInteger() const
{
return *value;
}
void Integer::setInteger( int newInteger )
{
*value = newInteger;
}
Integer& Integer::operator=( const Integer& rhInt )
{
*value = *rhInt.value;
return *this;
}
// IntegerTest.cpp
#include <iostream>
#include <cstdlib>
#include "Integer.h"
using namespace std;
void displayInteger( char* str, Integer intObj )
{
cout << str << " is " << intObj.getInteger() << endl;
}
int main( int argc, char* argv[] )
{
Integer intVal1;
Integer intVal2(10);
displayInteger( "intVal1", intVal1 );
displayInteger( "intVal2", intVal2 );
intVal1 = intVal2;
displayInteger( "intVal1", intVal1 );
return EXIT_SUCCESS;
}
This code works exactly as expected as is, it prints out:
intVal1 is 0
intVal2 is 10
intVal1 is 10
However if I remove the copy constructor it prints out something like:
intVal1 is 0
intVal2 is 10
intVal1 is 6705152
I don't understand why this is the case. My understanding is that the copy constructor is used when the assignment is to an object that doesn't exist. Here intVal1 does exist, so why isn't the assignment operator called?
The copy constructor is not used during assignment. Copy constructor in your case is used when passing arguments to displayInteger function. The second parameter is passed by value, meaning that it is initailized by copy contructor.
Your version of copy constructor performs deep copying of data owned by the class (just like your assignment operator does). So, everything works correctly with your version of copy constructor.
If you remove your own copy constructor, the compiler will generate one for you implicitly. The compiler-generated copy constructor will perform shallow copying of the object. This will violate the "Rule of Three" and destroy the functionality of your class, which is exactly what you observe in your experiment. Basically, the first call to displayInteger damages your intVal1 object and the second call to displayInteger damages your intVal2 object. After that both of your objects are broken, which is why the third displayInteger call displays garbage.
If you change the declaration of displayInteger to
void displayInteger( char* str, const Integer &intObj )
your code will "work" even without an explicit copy constructor. But it is not a good idea to ignore the "Rule of Three" in any case. A class implemented in this way either has to obey the "Rule of Three" or has to be made non-copyable.
The problem you're experiencing is caused by the default copy constructor, which copies the pointer but doesn't associate it with newly allocated memory (like your implementation of copy constructor does). When you pass object by value, a copy is created and when the execution goes out of scope, this copy is destructed. delete from the destructor invalidates the value pointer of intVal1 object, making it dangling pointer, dereferencing of which causes undefined behavior.
Debug outputs might be used to understand the behavior of your code:
class Integer {
public:
Integer() {
cout << "ctor" << endl;
value = new int;
*value = 0;
}
~Integer() {
cout << "destructor" << endl;
delete value;
}
Integer(int intVal) {
cout << "ctor(int)" << endl;
value = new int;
*value = intVal;
}
Integer(const Integer &rhInt) {
cout << "copy ctor" << endl;
value = new int;
*value = *rhInt.value;
}
Integer& operator=(const Integer& rhInt){
cout << "assignment" << endl;
*value = *rhInt.value;
return *this;
}
int *value;
};
void foo(Integer intObj) {
cout << intObj.value << " " << *(intObj.value) << endl;
}
Now output of this code:
Integer intVal1;
Integer intVal2(10);
foo( intVal1 );
foo( intVal2 );
intVal1 = intVal2;
foo( intVal1 );
is:
ctor
ctor(int)
copy ctor
0x9ed4028 0
destructor
copy ctor
0x9ed4038 10
destructor
assignment
copy ctor
0x9ed4048 10
destructor
destructor
destructor
which shows that copy constructor is used when passing objects by value. However, important to notice here is the destructor called upon the return from your function. And if you remove your implementation of copy constructor, then the output is:
ctor
ctor(int)
0x8134008 0
destructor
0x8134018 10
destructor
assignment
0x8134008 135479296
destructor
destructor
destructor
showing that the first copy called delete on the same pointer (pointing to 0x8134008) as was used by third copy later, where the memory pointed by this dangling pointer has been used.
Think about this call:
displayInteger( "intVal1", intVal1 );
You are creating a copy of intVal1 into the intObj parameter of displayInteger:
void displayInteger( char* str, Integer intObj )
{
cout << str << " is " << intObj.getInteger() << endl;
}
That copy will be pointing to the same int that intVal1 is. When displayInteger returns, intObj is destroyed, which will cause the int to be destroyed, and the pointer in intVal1 to be pointing to an invalid object. At that point all bets are off (A.K.A. undefined behavior) if you try to access the value. A similar thing happens for intVal2.
At a more general level, by removing the copy constructor, you are violating the Rule of Three, which typically leads to these kinds of problems.
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.