Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When reassigning variable, the destructor is not called.. (C++)

Tags:

c++

destructor

When a variable is reassigned, the destructor is not called:

Object foo = Object(a,b);
foo = Object(c,d);

so, the destructor will only be called at the end of the scope for Object(c,d), which can obviously cause problems. Now, in this specific case it doesn't bother me too much: it is enough to declare 2 different objects:

Object foo1 = Object(a,b);
Object foo2 = Object(c,d);

In this way the destructor of both objects will be called at the end.

However, there is a case when I necessarily need to reassign a variable, i.e. in an object constructor such as:

SuperObject(Point point1, Point point2) : delay_object_(DelayObject(0)) {
  double distance = distance(point1, point2);
  double delay = distance / speed;

  delay_object_ = DelayObject(delay);
}

In fact the DelayObject parameter is not easy to calculate (in this example I also omitted a few other passages), and I want to avoid doing it in the initialisation list.

I thought I can force the deletion by putting the object in the heap and explicitly calling the destructor:

SuperObject(Point point1, Point point2) : p_delay_object_(new DelayObject(0)) {
  double distance = distance(point1, point2);
  double delay = distance / speed;

  delete p_delay_object_;
  p_delay_object_ = new DelayObject(delay);
}

but this really looks ugly to me, as I prefer to use dynamic allocation only when strictly necessary. Am I missing something?

Cheers!

like image 509
Enzo Avatar asked Jul 04 '11 19:07

Enzo


2 Answers

"the destructor will only be called at the end of the scope for Object(c,d)"

False. Object(c,d) is a temporary, and its destructor is called at the end of the full-expression which creates it. In this case, that's the semi-colon at the end of foo = Object(c,d);. The destructor of foo is called at end-of-scope.

The assignment operator of Object should free or re-use resources already held by foo, and copy resources held by the temporary. Not necessarily in that order (see copy-and-swap).

Edit: in response to comment.

Object foo = Object(a,b);

Either

  1. A temporary is constructed using whatever two-argument constructor matches (a,b).
  2. foo is constructed using the copy-constructor, passing the temporary as argument.
  3. The temporary is destroyed.

Or

  1. foo is constructed using whatever two-argument constructor matches (a,b).

The implementation is free to do either - this is permitted by "copy constructor elision".

foo = Object(c,d);
  1. A temporary is constructed using whatever two-argument constructor matches (c,d).
  2. The assignment operator for class Object is called on foo, passing the temporary as argument.
  3. The temporary is destroyed.

Some time later, at the end of the scope, foo is destroyed.

In C++0x, move assignment would come into play if it exists for the class.

like image 70
Steve Jessop Avatar answered Nov 15 '22 16:11

Steve Jessop


You should overload the assignment operator, which would, conceptually, copy construct the existing object and destroy the old 'this'.

class Object {
  ...
  Object& operator= (const Object& other) {
     if (this != &other) {
       // copy 'other' into 'this'.
     }
     return *this;
  }
  ...
};

then the foo = Object(c,d); line should do what you expect.

(Also as @Steve Jessop mentioned, the temporary object Object(c,d) will also be destructed after before the end of the scope.)

See What is The Rule of Three?.

like image 33
kennytm Avatar answered Nov 15 '22 15:11

kennytm