Hello everybody!
I wrote an example about a copy constructor and the result wasn't what i expected. Here's the example:

#include <iostream>

using namespace std;

class A {
    public:
     A(const A& cp);
     A(double t[], int size);
     ~A();
     double *getTab() const { return tab; }
     double *tab;
     int size;
};

int main() {
    double t[] = {3.4, 5.6, 7.6};
   A obj1(t, 3);

   {
   A obj2 = obj1;
   cout << "ob1.tab[0] = {" << obj1.getTab()[0] << "}" << endl;
   cout << "ob2.tab[0] = {" << obj1.getTab()[0] << "}" << endl;
   }  //-->this is where obj2 is out of scope

   cout << "ob1.tab[0] = {" << obj1.getTab()[0] << "}" << endl;
   return 0;
}

A::A(const A& cp) : size(cp.size) {
    tab = new double[size];
    for (int i = 0; i < size; i++)
     tab[i] = cp.tab[i];
}

A::A(double t[], int size) {
    tab = new double[size];
   for (int i = 0; i < size; i++)
    tab[i] = t[i];
}

A::~A() {
  cout << "Destructor ~A() called\n";
  delete [] tab;
}

So, in the example above i created a class having a private double pointer and wrote and the copy constructor as well. Deliberately i created a block, where inside that block i declared object obj2 using my copy constructor:

A obj2 = obj1;

All went well but when i deleted my copy constructor and tested the code, surprisingly the code was executed correctly again! I thought that if i didn't write a copy constructor then, when obj2 would be out of scope the destructor would be called and eventually would delete the pointer. So i wouldn't be able to get the correct result. But i did get the correct result with the following line:

cout << "ob1.tab[0] = {" << obj1.getTab()[0] << "}" << endl;

Am i missing something? Thank you for your time!

Recommended Answers

All 9 Replies

Two points:

1) Why do you think your code was executed correctly? Is it not possible that it just happened to appear to be correct by coincidence? How would you go about proving that it was executed correctly even without a copy constructor.

2) If you have a copy constructor, you should probably also have an operator= member.

The code that you wrote correctly works in both cases because you didn't actually do anything with obj2 or obj1.

Note you wrote this: cout << "ob2.tab[0] = {" << obj1.getTab()[0] << "}" << endl; That should have been obj2.getTab() not obj1.getTab() Additionally you have incorrectly written the constructor: This should core dump in most circumstances e.g. you have written:

A::A(double t[], int size)     // size MASKS the variable size in the class 
{
   tab = new double[size];
   for (int i = 0; i < size; i++)
    tab[i] = t[i];
}

It should have been written like this:

A::A(double t[], int s) :
  size(s),
{
   if (size>0)
     {
       tab = new double[size];
       for (int i = 0; i < size; i++)
         tab[i] = t[i];
     }
   else
     tab=0;
}

THEN if you remove the copy constructor, you get a core dump BUT it occurs on the deletion operator of obj1. To understand that, you must note what happens if you don't actually provide a copy constructor. The compile substitutes a simple copy constructor that makes a shallow copy of everything. In this case, the variable tab, is just copied, i.e. both obj1.tab and obj2.tab point to the same memory location, however, obj2.tab is deleted and everything is ok, [you have had one allocation and one deletion.] The get tab[0] command actually works, since there is no check to see that the memory hasn't been deleted, and nothing else has happened for the program to fill/change that memory. Then however, you try to delete it AGAIN when you delete the obj1 for the next time, nasty core dump.

Note: I compiled it with g++/no optimization. You might get different results with different compilers/optimization.

Hope that helps what I think is quite a tricky C++ concept.

Firstly, thank you all for your instant messages! I appreciate that..

2) If you have a copy constructor, you should probably also have an operator= member.

'

arkoenig i think that in my code i don't need to overload operator=. Is it mandatory to use operator= overloading every time i write a copy constructor? I know that when you deal with a class that has dynamic private members then probably you'll have to write a destructor, overload operator= and write a copy constructor too. But is it always necessary to overload operator= even if you didn't use an expression:

obj1 = obj2

I'm not 100% sure..i'd like an extra opinion...

The compile substitutes a simple copy constructor that makes a shallow copy of everything. In this case, the variable tab, is just copied, i.e. both obj1.tab and obj2.tab point to the same memory location, however, obj2.tab is deleted and everything is ok, [you have had one allocation and one deletion.] The get tab[0] command actually works, since there is no check to see that the memory hasn't been deleted, and nothing else has happened for the program to fill/change that memory.

StuXYZ exactly this is what i had on my mind..that's why it seemed weird to me and wondered: "destructor ~A() deleted obj2.tab and obj1.tab points to the same memory location. Why do i get an answer?" How can i check if a chunk of memory is actually deleted? So when a destructor executes its job, doesn't actually delete the content of the specific memory location. It just frees the specific memory location and lets me reuse it whenever i want...Is this what's really happening? Is it possible to get different results with a different compiler? Thank you again for your time..

Is it mandatory to use operator= overloading every time i write a copy constructor?

Unless you're going to make operator= private, it's a good idea to include it as well as a copy constructor and a destructor. Because if you need a copy constructor, more often than not you need to deal with assignments and destruction as well (the so called "Big Three"). The defaults typically aren't sufficient if any one of the big three are needed.

Thank you Narue for your answer! What's your opinion about this?

How can i check if a chunk of memory is actually deleted? So when a destructor executes its job, doesn't actually delete the content of the specific memory location. It just frees the specific memory location and lets me reuse it whenever i want...Is this what's really happening? Is it possible to get different results with a different compiler?

I can see several ways of answering that question depending on what you mean by "actually deleted" and the reason why you would want to check that. Can you elaborate a little bit?

Well, my basic question was that without a copy constructor obj1.tab and obj2.tab pointed to the same memory location, destructor ~A() deleted obj2.tab (the common memory location) so when i was writing

cout << "obj1.tab[0] = {" << obj1.getTab()[0] << "}" << endl;

i assumed that my code will give me no output (since obj2.tab had been already deleted..) but it did give me the first element of tab array. StuXYZ answered that

The get tab[0] command actually works, since there is no check to see that the memory hasn't been deleted, and nothing else has happened for the program to fill/change that memory

That confused me a little bit...that's why i asked: What does the destructor eventually do? Does it just free memory but leaves the content of that memory location untouched?
Or does it free the specific memory location but at the same time deletes its content..? Is there a possibility to get different results if i use a different compiler?
I hope i'm clear now..Thank you again!

You're getting into the realm of undefined behavior, which makes it harder to answer conclusively. In theory, once a pointer is deleted, the memory block it points to is no longer available, even if you have ten other pointers to the same block. All of those other pointers are silently invalidated. Deleting a pointer does not clear the memory, so if you dereference the pointer before the memory is reclaimed for other purposes, you'll likely get the same data that was originally stored there.

Does that answer your question?

Thank you Narue, i knew that this subject was a bit tricky...but you were totally clear! Cheers!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.