0

After searching a lot, at least this question helped me to understand the difference of using copy constructor and assignment operator
My question is about this line
instance has to be destroyed and re-initialized if it has internal dynamic memory
If I initialize an instance like
Object copyObj = null; and then then assign copyObj = realObj then still this overhead (destruction and re-initialization) remains?
If not, then Now in this scenario, why should I use Copy Constructor instead of direct assigning the object

Community
  • 1
  • 1
Despicable
  • 3,797
  • 3
  • 24
  • 42
  • 5
    You are asking a Java question but referng to a C++ question. Java doesn't support operator overriding. – André Stannek Jun 21 '13 at 06:39
  • I am referring to a concept.But I need to understand this concept in java prespective – Despicable Jun 21 '13 at 06:41
  • assignment operators on objects are too different in Java and C++; in Java, object assignments are actually pointer assignments. – Alex Shesterov Jun 21 '13 at 06:44
  • @downvoter please specify the reason – Despicable Jun 21 '13 at 06:44
  • 1
    @Despicable: I'm not the one who downvoted, but I guess the reason is likely the presence of both the C++ and Java tags. Usually, people of these two worlds rarely collapse and speaking of one in terms of the other doesn't really make sense. – ereOn Jun 21 '13 at 07:05
  • So thats why you down voted? And FUI I just tagged it to Java, I guess @maroun maroun edited my question and tagged it to both – Despicable Jun 21 '13 at 07:07
  • @Despicable: You really need to read more carefully. I precisely said **I wasn't the one who downvoted**. Just look at my [downvote stats](http://stackoverflow.com/users/279259/ereon?tab=votes&sort=downvote) to make sure of that. – ereOn Jun 21 '13 at 07:09
  • @Despicable: No offense taken. I never got an answer from anyone who downvoted my questions or answers. I only tried to give an explanation that seemed likely because I'm pretty sure you never will as well. But for all I know, it could also just be someone that doesn't like Java, C++, your nickname or the colors of your avatar :/ – ereOn Jun 21 '13 at 07:20

3 Answers3

5

The concept of using a copy constructor by overriding the = simply does not exist in Java. You can't override operators. The concept of a copy constructor in Java works like this:

public class MyType {

    private String myField;

    public MyType(MyType source) {
        this.myField = source.myField;
    }
}

A copy constructor is a constructor that takes a parameter of the same type and copies all it's values. It is used to get a new object with the same state.

MyType original = new MyType();
MyType copy = new MyType(original);
// After here orginal == copy will be false and original.equals(copy) should be true
MyType referenceCopy = original
// After here orginal == referenceCopy will be true and original.equals(referenceCopy) will also be true

The = operator does the same: Assigning an object to a variable. It produces no overhead. The thing that can differ in runtime is the constructor call.

André Stannek
  • 7,773
  • 31
  • 52
  • I know `=` does the same.I also know How can we create the Copy constructor.I just want to know Why should I use Copy construtor when I can do this by `=` .Your whole answer is simply irrelevant – Despicable Jun 21 '13 at 06:50
  • The point is you CAN'T do this by `=` in Java! That's what I tried to explain to you. You CAN'T overload `=` so that it implicitly calls a copy constructor. – André Stannek Jun 21 '13 at 06:51
  • Hold on. isn't it possible `Object obj1 = new Object(); Object Obj2 = obj1;` ... ??? – Despicable Jun 21 '13 at 06:54
  • 3
    Yes, but the second one doesn't call a copy constructor. After that you simply have two variables pointing to the same object. A copy constrcutor creates a new object. That's exactly what I wrote in my answer. – André Stannek Jun 21 '13 at 06:55
  • Tried to clarify my answer. – André Stannek Jun 21 '13 at 06:57
  • It means that by using copy constructor we have the same copy but in two different memories (real one and copied one) but by using `=` both are reffers to same memory – Despicable Jun 21 '13 at 06:59
  • I would use the word "equal copy" instead of "same copy" but basically yes. – André Stannek Jun 21 '13 at 07:00
  • Good enough.No hard feelings – Despicable Jun 21 '13 at 07:02
3

A Copy constructor allows you to keep two references; one to the "old" object, one to the "new". These objects are independent ( or should be depending upon how deep you allow the copy to be )

If you do a reassignment, you only have a reference to the "new" object. The "old" object will no longer be accessible ( assuming there are no other references to it ) and will be eligible for garbage collection.

It comes down to what it is your trying to achieve. If you want an exact copy of the object, and you want this object to have an independent life of its own, use a copy constructor. If you just want a new object and don't care about the old one, reassign the variable.

PS - I have to admit, I didn't read the question you linked to ..

Freak
  • 6,786
  • 5
  • 36
  • 54
DaveH
  • 7,187
  • 5
  • 32
  • 53
  • Yes this is my answer.Answer from a person who undestand the question rather than commenting on absurd things – Despicable Jun 21 '13 at 06:47
  • 2
    I think you're being a bit tough on Andre, who is saying exactly the same thing as me – DaveH Jun 21 '13 at 06:49
  • Also @Despicable the fact that you confuse two significantly different concepts i.e. in c++ vs java. I was about to write an answer for c++ only to realize you are looking for java oriented explaination, which i don't feel qualify enough to answer for certain. – fkl Jun 21 '13 at 07:18
1

First some basics about copy construction and copy assignment in C++ and Java

C++ and Java are two very different beasts due to object semantics in C++ and Reference semantics in Java. What I mean by this is:

SomeClass obj = expr;

In C++ this line denotes a new object that gets initialized with expr. In Java, this line creates not a new object but a new reference to an object, and that reference refers to what ever the expression gives. Java references can be null, meaning "no object". C++ objects are, so there is no "no object"-object ;-) Java references are very much like C++ pointers. The only thing that can make the distinction difficult is that while C++ has pointers and objects and dereferences pointers with ->, in Java everything is a reference (except int and a few other basic types), and accessing objects through references uses ., wich easily can be confused with access to "direct" objects in C++. "Everything is a reference" means, that any object (except int & Co.) is conceptually created on the heap.

Having said that, let's have a look at assignments and copies in both languages.

Copy construction means the same in both languages, you essentially create a new object that is a copy of another. Copy constructor definition is similar:

SomeClass(SomeClass obj) { /* ... */ }         //Java
SomeClass(SomeClass const& obj) { /* ... */ }  //C++

The difference is only that C++ explicitly has to declare the parameter as a reference, while in Java everything is a reference anyways. Writing the first line in C++ would define a constructor that takes it's argument by copy, i.e. the compiler would have to create a copy already, using the copy constructor, for which it has to create a copy,... - not a good idea.

Using copy construction in the two languages will look like this:

SomeClass newObj = new SomeClass(oldObj);     //Java
SomeClass newObj = oldObj;                    //C++ object
SomeClass* ptrNewObj = new SomeClass(oldObj); //C++ pointer

When you look at the first and third line, they look essentially the same. This is because they are essentially the same, since Java references are essentially like pointers in C++. Both expressions create a new object that can outlive the function scope it is created in. The second line creates a plain C++ object on the stack, wich does not exist in Java. In C++, copies are also created implicitly by the compiler eg. when an object is passed to a function that accepts its parameter by value instead of by reference.

Defining copy assignment: In C++, you can define operator= wich (normally) assigns the values of an object to an already existing object, discarding the old values of the object you assign to. If you don't define it yourself, the compiler will do it's best to generate one for you, doing a plain elementwise copy of the objects' elements. In Java, you cannot overload operators, so you will have to define a method, called e.g. assign:

void assign(SomeObject other)                  {/* ... */} //Java
SomeObject& operator=(SomeObject const& other) {/* ... */} //C++

Note thet here again we explicitly declare the parameter as reference in C++ but not in Java.

Using copy assignment:

objA = objB;        //C++ copy assignment
objA = objB;        //Java ref assignment
ptrObjA = ptrObjB;  //C++ pointer assignment
objA.assign(objB);  //Java 
objB.change();

Here the first two lines look exactly the same but could not be more different. Remember that in C++, objA and objB deonte the objects themselves, while in Java they are only references. So in C++ this is copy assignment on objects, meaning you finish with two objects that have the same content. After changing objB you will have objA with the value that objB had before the assignment, while objB has changed.
In Java (line 2) that assignment is an assignment of references, meaning after that the two references objA and objB refer to the very same object, while the object previously referred ba objA is not referred to any more and so it will be garbage collected. Calling objB.change() will change the single object both references point to and accessing it through the reference objA will reveal these changes.
Again it's (nearly) the same with C++ pointers. You see you cannot distinguish the syntax of object and pointer assignment, it's all determined by the types that get assigned. The difference with C++ is that it has no garbace collector and you end up with a memory leak because the object ptrObjA pointed to can not be deleted any more.

About your question:

Consider a C++ class:

class X {
  int* pi;
  unsigned count;
public:
  X(X const&);
  X& operator= (X const&);
  ~X();
};

Suppose each X object allocates it's own dynamic array of ints, the pointer to it gets stored in pi. Since C++ has no garbage collection, the X objects have to care themselves for their allocated memory, i.e. they have to destroy it manually:

X::~X() { delete[] pi; }

A copy constructor will copy the dynamic array of the original, so the two do not conflict while using the same array. This is called deep copy and is used equally in Java and C++:

X::X(X const& other) : pi(NULL), count(0) {
  pi = new int[other.count];  //allocates own memory
  count = other.count;
  std::copy(other.pi, other.pi+count, pi); //copies the contents of the array
}

Now to the qoute in your question: Consider two objects x1 and x2 and the assignment x1 = x2. If you leave everythign to the compiler, it will generate an assignment operator like this:

X& X::operator=(X const& other) {
  pi = other.pi;
  count = other.count;
}

In the first line x1.pi gets the pointer value of x2.pi. Like I explained in the section about copy assignment, this will lead to both pointers pointing to the same array, and the array previously owned by x1 will be lost in space, meaning you have a leak and odd behavior when both objects work on their shared array.
The correct implementation would be:

X& X::operator=(X const& other) {
  delete[] pi;           //1

  pi = new int[other.count];  //allocates own memory
  count = other.count;
  std::copy(other.pi, other.pi+count, pi); //copies the contents of the array
}

Here you see what the quote says: First, the object is "cleaed up", i.e. the memory is freed, essentially doing what the destructor does ("instance has to be destroyed"). Then, the deep copy is performed, doing what the copy constructor does ("...and re-initialized").

This is called the "Rule of Three": If you have to write your own copy constructor (because the generated one does not what you want it to do), you will mostly have to write your own destructor and assignment operator as well. Since C++11 it has become the "Rule of Five", because you have move assignment and move construction that have to be considered as well.

Pablo Rivas
  • 941
  • 9
  • 16
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90