create a deep copy by using copy constructor in c++ - c++

I'm beginner in C++ and I have a problem with my copy constructor: I need to do a deep copy, because my class has a pointers. I already defined a copy constructor and also I create an object N1(2,3) from my class Number. A second object N2 is intialized by using copy constructor.
But the copy constructor doesn't do a deep copy because, when I change the value of object N1, object N2 also has its values changed. I want to have two separate objects by using copy constructor.
My class Number:
class Number
{
private:
int* a;
int* b;
public:
//default constructor:
Number() {
a = new int;
b = new int;
*a = 0;
*b = 0;
}
//constructor with arguments:
Number(int val1, int val2) {
a = new int;
b = new int;
*a = val1;
*b = val2;
}
//copy constructor:
Number(const Number& other) {
a = new int;
b = new int;
*a = *(other.a)
*b = *(other.b);
}
//getters and setters:
int getA() {
return *a;
}
int getB() {
return *b;
}
void setA(int val) {
*a = val;
}
void setB(int val) {
*b = val;
}
//method print:
void print() {
cout << "value of a: " << *a << " value of b: " << *b << endl;
}
};
My main:
int main()
{
Number N1(2,3), N2;
N1.print(); //2-3
N2.print(); //0-0
N2 = N1;
N1.print(); //2-3
N2.print(); //2-3
N1.setA(12);
N1.print(); //12-3
N2.print(); //12-3 i want object N2 have 2-3 values not 12-3 like N1
//i want to separate N1 from N2 by using copy constructor
}
I'm trying to define this copy constructor but it's not working:
//copy constructor:
Number(const Number& other) {
a = new int;
b = new int;
*a = *(other.a)
*b = *(other.b);
}

The code, N2 = N1;, does not invoke the copy constructor because N2 has already been constructed. Rather, it calls the assignment operator. As you have not provided a definition for that, the default is to make a shallow copy (i.e. just copy/overwrite the actual pointers, as you observe).
You need to define a deep-copying assignment operator; something like this:
// assignment operator:
Number& operator=(const Number& other) {
*a = *(other.a);
*b = *(other.b);
return *this;
}
Note, however, that were you to use the = N1 syntax in your declaration of N2 (as below), then that would call the copy constructor:
Number N2 = N1; // This calls the copy constructor

The issue you're seeing is lack of Complete Rule of 0/3/5.
And the fact that you are not invoking your copy constructor. You are invoking the assignment operator, which has been provided for you, and is shallow.
The line Number N1(2,3), N2; has declared N2 using the default constructor.
The line N2 = N1; then shallow copies N1 because you didn't provide operator=().
If you wanted to invoke the copy constructor, you have to do so at the time of declaration. It is a constructor, after all.
Something like Number N2(N1);.
In order to complete your code, you still need to write a destructor as well as assignment operator. Then it's time to learn about move semantics.

Related

Assignment operator as copy constructor

Assignment operator can be used to copy the value of one object to another
instead of using copy constructor,then why we required a copy constructor?
class example
{
int data;
public:
example()
{
}
example(int x)
{
data = x;
}
};
int main()
{
example a(50);
example a(b);
//same can be done with the assignment operator
//b = a;
return 0;
}
Because at the point of calling a copy constructor, the object being copied to doesn't yet exist.
An assignment operator assigns the value of another object to one that does exist.
Devices such as member initialisation can be used with a copy constructor, but are not available on assignment. Furthermore it's possible to create a const object using a copy constructor.
Furthermore, the assignment operator typically returns a reference to self.
So a copy constructor and the assignment operator probably will leave the mutated object in an identical state, but it doesn't necessarily have to be the case.
As Bathsheba already said: A copy constructor creates a new object, an assignment operator assigns values to an already existing object. One needs to construct a new object, the other needs to handle whatever happens if you assign the values from one object to another. Take this example:
class Foo
{
public:
Foo(int x) { someValue = x; };
int getValue() const { return someValue; };
private:
int someValue;
}
class Bar
{
public:
Bar(int y)
{
myFoo = new Foo(y);
myValue = y + 1;
myInitDone = true;
};
Bar(const Bar& other)
{
//myFoo was not yet initalized, so no need to clean it up
myFoo = new Foo(other.myFoo->getValue());
myValue = other.myValue;
myInitDone = true;
}
Bar& operator=(const Bar& other)
{
delete myFoo; // If we don't clean up myFoo here we leak memory
myFoo = new Foo(other.myFoo->getValue());
myValue = other.myValue;
// myInitDone is only set during construction due to [reason]
}
private:
Foo* myFoo;
int myValue;
bool myInitDone;
}
The copy constructor needs to set myInitDone (which is only done during constuction because [insert reason here]), while the assigment operator needs to clean up myFoo or it will leak memory.

why is the iterator not initialized in this code

In the code below, Class A has a vector of ints. Class B inherits from A and has an iterator to the vector. The constructor of B initializes the iterator of B. But when we print, we get garbage. Why does the cout in main print garbage? Am I missing something?
#include <iostream>
#include <vector>
class A {
public:
A() {}
A(const A& copyFrom) : intList(copyFrom.intList) {} //copy constructor
virtual ~A() {}
void populateList()
{
for(int i=10; i<100; i++)
{
intList.push_back(i);
}
}
protected:
std::vector<int> intList;
};
class B : public A {
public:
B() : A() {}
B(const A& a) : A(a), intIt(intList.begin())
{
std::cout << "constructor with base class param called" << std::endl;
}
B(const B& b) : A(b), intIt(intList.begin()) //copy constructor
{
std::cout << "copy constructor called" << std::endl;
}
std::vector<int>::iterator intIt;
};
int main() {
A a;
a.populateList();
B b ;
b = B(a);
std::cout << *b.intIt << std::endl; //prints garbage. why?
}
Thanks!
B b ;
b = B(a); //the copy constructor of B is not called here. Why?
The operation in that line is assignment, not copy constructor. The copy constructor would be:
B b = someotherB;
Note that semantically this is also copy-constructing:
B b = B(a);
But the compiler will more often than not elide the copy contruction by creating B(a) in place of b.
The expression b = B(a) separated from declaration is assignment, not copy construction. This is one of the confusing things about C++:
Foo x(y); // copy-construction
Foo x = y; // also copy-construction, equivalent to the above
Foo x; x = y; // default-construction followed by assignment, different
// (and possibly less efficient) than the above
Failing to define an assignment operator will create a default one that performs member-wise assignment. This is OK for the intList member, but the assigned intIt will keep pointing to the old list, which in your case belongs to the temporary reference to B created by the B(a) expression. As soon as this reference is destroyed (which is at the end of the outermost expression), its intList is destroyed and the iterator becomes invalid.
In other words, B b; b = B(a) is equivalent to:
B b; // constructor
{
B tmp(a); // copy constructor
b = tmp; // member-wise assignment
// at this point, b.intList is a copy of tmp.intList, but b.intIt
// points to the beginning of tmp.intList, not to the beginning of
// b.intList
}
// tmp is destroyed and b.intIt now points to the beginning of a deleted list
It is your responsibility to define an assignment operator that maintains the invariant of intIt referring to an element in intList; for example:
B& operator=(const B& rhs)
{
intList = rhs.intList;
intIt = intList.begin() + (rhs.intIt - rhs.intList.begin());
std::cout << "assignment called" << std::endl;
return *this;
}
Also note that all iterators into the vector are invalidated when you change the size of the vector, even if you only append with push_back(). So populateList(), and other methods that can change the size of the vector should be overridden in B to also recalculate intIt. For these reasons it would be a better idea to avoid using an iterator and simply store the position into the vector, and have a function that returns intList.begin() + pos, thus creating an iterator on-demand that is guaranteed to be valid. Then you wouldn't need to define neither a copy-constructor nor an assignment operator, as the compiler-supplied defaults would work just fine.
The Copy construction will not be called because you are not assigning object of same class
b = B(a); //the copy constructor of B is not called here. Why?
in above code below constructor will be called because you are passing object of type A
B(const A& a) : A(a), intIt(intList.begin())
{
std::cout << "constructor with base class param called" << std::endl;
}
Iterator value will not be usable because you are not initializing it
std::cout << *(b.intIt) << std::endl; //prints garbage. why?
you need to initalize it
std::vector<X>::iterator iter; //no particular value
iter = some_vector.begin(); //iter is now usable

Temporaries created during assignment operation

if every assignment creates a temporary to copy the object into lvalue, how can you check to see in VC++ 8.0?
class E
{
int i, j;
public:
E():i(0), j(0){}
E(int I, int J):i(I), j(J){}
};
int main()
{
E a;
E b(1, 2);
a = b //would there be created two copies of b?
}
Edit:
Case 2:
class A
{
int i, j;
public:
A():i(0), j(0){}
};
class E
{
int i, j;
A a;
public:
E():i(0), j(0){}
E(int I, int J):i(I), j(J){}
E(const E &temp)
{
a = temp; //temporary copy made?
}
};
int main()
{
E a;
E b(1, 2);
a = b //would there be created two copies of b?
}
From your comment, you made it clear that you didn't quite understand this C++-FAQ item.
First of all, there are no temporaries in the code you presented. The compiler declared A::operator= is called, and you simply end up with 1 in a.i and 2 in a.j.
Now, regarding the link you provided, it has to do with constructors only. In the following code :
class A
{
public:
A()
{
s = "foo";
}
private:
std::string s;
};
The data member s is constructed using std::string parameterless constructor, then is assigned the value "foo" in A constructor body. It's preferable (and as a matter of fact necessary in some cases) to initialize data members in an initialization list, just like you did with i and j :
A() : s("foo")
{
}
Here, the s data member is initialized in one step : by calling the appropriate constructor.
There are a few standard methods that are created automatically for you if you don't provide them. If you write
struct Foo
{
int i, j;
Foo(int i, int j) : i(i), j(j) {}
};
the compiler completes that to
struct Foo
{
int i, j;
Foo(int i, int j) : i(i), j(j)
{
}
Foo(const Foo& other) : i(other.i), j(other.j)
{
}
Foo& operator=(const Foo& other)
{
i = other.i; j = other.j;
return *this;
}
};
In other words you will normally get a copy constructor and an assignment operator that work on an member-by-member basis. In the specific the assignment operator doesn't build any temporary object.
It's very important to understand how those implicitly defined method works because most of the time they're exact the right thing you need, but sometimes they're completely wrong (for example if your members are pointers often a member-by-member copy or assignment is not the correct way to handle the operation).
This would create a temporary:
E makeE( int i, int j )
{
return E(i, j);
}
int main()
{
E a;
a = makeE( 1, 2 );
E b = makeE( 3, 4 );
}
makeE returns a temporary. a is assigned to the temporary and the assignment operator is always called here. b is not "assigned to", as it is being initialised here, and requires an accessible copy-constructor for that to work although it is not guaranteed that the copy-constructor will actually be called as the compiler might optimise it away.

When assigning in C++, does the object we assigned over get destructed?

Does the following code fragment leak? If not, where do the two objects which are constructed in foobar() get destructed?
class B
{
int* mpI;
public:
B() { mpI = new int; }
~B() { delete mpI; }
};
void foobar()
{
B b;
b = B(); // causes construction
b = B(); // causes construction
}
The default copy assignment operator does a member-wise copy.
So in your case:
{
B b; // default construction.
b = B(); // temporary is default-contructed, allocating again
// copy-assignment copies b.mpI = temp.mpI
// b's original pointer is lost, memory is leaked.
// temporary is destroyed, calling dtor on temp, which also frees
// b's pointer, since they both pointed to the same place.
// b now has an invalid pointer.
b = B(); // same process as above
// at end of scope, b's dtor is called on a deleted pointer, chaos ensues.
}
See Item 11 in Effective C++, 2nd Edition for more details.
Yes, this does leak. The compiler automatically provides an extra method because you have not defined it. The code it generates is equivalent to this:
B & B::operator=(const B & other)
{
mpI = other.mpI;
return *this;
}
This means that the following stuff happens:
B b; // b.mpI = heap_object_1
B temp1; // temporary object, temp1.mpI = heap_object_2
b = temp1; // b.mpI = temp1.mpI = heap_object_2; heap_object_1 is leaked;
~temp1(); // delete heap_object_2; b.mpI = temp1.mpI = invalid heap pointer!
B temp2; // temporary object, temp1.mpI = heap_object_3
b = temp1; // b.mpI = temp2.mpI = heap_object_3;
~temp1(); // delete heap_object_3; b.mpI = temp2.mpI = invalid heap pointer!
~b(); // delete b.mpI; but b.mpI is invalid, UNDEFINED BEHAVIOR!
This is obviously bad. This is likely to occur in any instance that you violate the rule of three. You have defined a non-trivial destructor and also a copy constructor. You have not defined a copy assignment, though. The rule of three is that if you define any of the above, you should always define all three.
Instead, do the following:
class B
{
int* mpI;
public:
B() { mpI = new int; }
B(const B & other){ mpI = new int; *mpi = *(other.mpI); }
~B() { delete mpI; }
B & operator=(const B & other) { *mpI = *(other.mpI); return *this; }
};
void foobar()
{
B b;
b = B(); // causes construction
b = B(); // causes construction
}
You're constructing three objects, and all will be destructed. The problem is that the default copy-assignment operator will do a shallow copy. That means the pointer is copied over, which causes it be be deleted more than once. This causes undefined behavior.
This is the reason behind the rule of 3. You have a destructor but not the other two. You need to implement a copy constructor and copy assignment operator, both of which should do a deep copy. This means allocating a new int, copying the value over.
B(const B& other) : mpI(new int(*other.mpI)) {
}
B& operator = (const B &other) {
if (this != &other)
{
int *temp = new int(*other.mpI);
delete mpI;
mpI = temp;
}
return *this;
}
As pointed out several times, you've violated the rule of three. Just to add to the links, there is a great discussion of this on stack overflow: What is The Rule of Three?
Just to offer a different approach to solving the problems of the code I originally posted, I think I could keep the pointer in class B, but take the memory mangement out. Then I need no custom destructor, and so I don't violate the rule of 3...
class B
{
int* mpI;
public:
B() {}
B(int* p) { mpI = p; }
~B() {}
};
void foobar()
{
int* pI = new int;
int* pJ = new int;
B b; // causes construction
b = B(pI); // causes construction
b = B(pJ); // causes construction
delete pI;
delete pJ;
}

Is this C++ reassignment valid?

Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);