Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing a Destructor from Running in C++

Tags:

c++

I would like to ensure that an object's destructor does not run. Is there any way to do this other than putting the object on the heap and not calling delete?

like image 957
Dave Avatar asked Feb 03 '12 02:02

Dave


1 Answers

I'm surprised that nobody mentioned completely C++ standard compliant solution with union. In union no constructor even destructor is called automatically for members. Even in case there is only one member in the union. All that must be done "manually":

  • constructor can be called through so called "placement new" (or from a constructor init list introduced by :),

  • destructor can be called by explicit call of destructor method.

Demo:

class MyObj {
  int i;
public:
  MyObj(int i_) : i(i_) { std::cout << i << " constructed" << std::endl; }
  MyObj(MyObj const &src) : i(src.i + 100) { std::cout << src.i << " copied to new " << i << std::endl; }
  ~MyObj() { std::cout << i << " destroyed" << std::endl; }
};

class OptDestr {
  bool callDestructor;
  union { MyObj o; };  // Only allocated, but no constr/destr is called automatically

public:
  // Constructor
  OptDestr(int i, bool callDestructor_) : callDestructor(callDestructor_), 
    o(i) // calls MyObj constructor
  { }
  // OR alternatively:
  OptDestr(int i, bool callDestructor_) : callDestructor(callDestructor_) {
    new (&o)MyObj(i);  // placement new - does NOT allocate, just calls constructor
  }

  // Copy constructor
  OptDestr(OptDestr const &src) : callDestructor(src.callDestructor),
    o(src.o)  // explicit call of MyObj copy-constructor
  { }
  // OR alternatively:
  OptDestr(OptDestr const &src) : callDestructor(src.callDestructor) {
    new (&o)MyObj(src.o);  // placement new - no allocation, just explicitly calls copy-constructor of MyObj
  }

  // Destructor
  ~OptDestr() {
    if (callDestructor) o.~MyObj();  // explicit call of destructor
  }
};


int main() {
  OptDestr d1(1, false /*callDestructor*/);
  OptDestr d1_copy(d1);
  OptDestr d2(2, true /*callDestructor*/);
  OptDestr d2_copy(d2);
}

The output of the program is the following:

1 constructed
1 copied to new 101
2 constructed
2 copied to new 102
102 destroyed
2 destroyed

You can see that there is no 1 destructed neither 101 destructed. I would guess that types like std::Optional are implemented in a similar way.

like image 167
Jarek C Avatar answered Oct 06 '22 00:10

Jarek C