views:

152

answers:

3

I am having problems using my custom class with a std::map. The class dynamically allocates memory for members, and I do not want to use pointer in the map because I want to ensure that the class takes care of deleting all allocated memory. But the problem I am having is after I add item to map, when that block of code goes out of scope, the objects destructor is called even though it is still on the map. I made a fake bit of code below that shows what I mean. The output is: So the problem is why is the final destructor being called? Thanks in advance and sorry for the long question.

Constructor Called Num:0034B7E8
Default Constructor Called Num:00000000
Copy Constructor Called Num:CCCCCCCC
Copy Constructor Called Num:CDCDCDCD
destructor called Num:CCCCCCCC
destructor called Num:00000000
destructor called Num:0034B7E8
Inserted Num:0034B7E8



class myClass
{
public:
  myClass(int num) 
  {
     mnNum = new int();
     cout << "Constructor Called Num:" << mnNum << endl;
   }

   myClass() : mnNum(NULL)
   {
      cout << "Default Constructor Called Num:" << mnNum << endl;
   }

   myClass(const myClass &copy) 
   {
      mnNum = new int(copy.mnNum);
      cout << "Copy Constructor Called Num:" << mnNum << endl;
   }

   ~myClass()
   {
      delete mnNum;
      mnNum = NULL;
   }

   int* mnNum;

 };

 map<string,myClass> mvMyMap;

 void testFunction()
 {
     myClass lcObj(1);

     mvMyMap["Test"] = lcObj;
 }


 int _tmain(int argc, _TCHAR* argv[])
 {
     testFunction();
     cout << "Inserted Num:" << mvMyMap["Test"].mnNum << endl;
 return 0;
  }
A: 

Your constructor ignores the num parameter and never initializes mnNum from it. It should look like:

myClass(int num) 
{
    mnNum = new int(num);
    cout << "Constructor Called Num:" << mnNum << endl;
}

You also need to adjust your copy constructor like this:

myClass(const myClass &copy) 
{
    mnNum = new int(*copy.mnNum);
    cout << "Copy Constructor Called Num:" << mnNum << endl;
}

edit

Derek Ledbetter pointed out that we need an assignment operator, too. And I would suggest making the destructor virtual.

Steven Sudit
There's no need to make the destructor virtual unless this is meant to be a polymorphic base class. Which it isn't.
Mike Seymour
@Mike, if you're not going to allow inheritance, then I agree that there's no need for a virtual destructor. However, the code does currently allow it. If you want to omit the virtual then I believe you should also modify the code to prevent inheritance. There's no `sealed`, but there are equivalent ways of doing this.
Steven Sudit
The class has value semantics (i.e. it's copyable and assignable) and no virtual functions, so it can't be used as a polymorphic base class. Adding a virtual destructor just in case someone does something silly will just make wrong code differently wrong.
Mike Seymour
@Mike, I agree that this class shouldn't be inherited from. There are some cases where we want to inherit from a base class that lacks virtual methods, though these are rare and this is not one of them. In those cases, we'd want the virtual destructor to prevent leaks. In this case, we just want to make inheritance impossible. For techniques, see http://stackoverflow.com/questions/2184133/prevent-class-inheritance-in-c
Steven Sudit
You really don't want to jump through hoops trying to prevent people from wilfully abusing the class, especially if it incurs a runtime cost. Just leave it as a stand-alone non-polymorphic type with value semantics, and trust people to use it sensibly (or add a comment if you don't trust them). Inheriting from such a type isn't necessarily wrong, even if you (or I) can't think of a valid reason to. It's only an error if you also delete the wrong type.
Mike Seymour
I *half* agree with you. I'd be willing to jump through a *small* hoop to prevent abuse, so long as it doesn't involve any significant run-time cost. Maybe a few years of C# has worn the sharp edge off my "we trust you to sink or swim" C++ attitude, or maybe I've just mellowed with age, but I'd rather make errors impossible than have to track them down.
Steven Sudit
+9  A: 

myClass needs a custom assignment operator, in addition to the copy constructor. So when you make an assignment, you'll leak the original value on the left, and eventually double delete the value on the right.

Derek Ledbetter
Good catch. Really, a smart pointer is probably the best way to go here. This may mean a smart pointer in the class, or just storing a smart pointer *to* the class, in the map.
Steven Sudit
Yes I forgot the rule of three which states that I should have an assignment operator when I have a copy constructor and destructor.
CptanPanic
A: 

Very nice Site number one topic Thanks you..

custom assignment