防止析构函数在C++中运行

Dav*_*ave 3 c++

我想确保对象的析构函数不会运行.有没有办法做到这一点,除了把对象放在堆上而不是调用delete?

Jar*_*k C 13

我很惊讶没有人提到完全符合 C++ 标准的解决方案union。在union没有构造函数中,甚至会自动为成员调用析构函数。即使工会中只有一名成员。所有这些都必须“手动”完成:

  • 构造函数可以通过所谓的“placement new”(或从由 引入的构造函数初始化列表:)调用,

  • 析构函数可以通过析构函数的显式调用来调用。

演示:

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);
}
Run Code Online (Sandbox Code Playgroud)

程序的输出如下:

1 constructed
1 copied to new 101
2 constructed
2 copied to new 102
102 destroyed
2 destroyed
Run Code Online (Sandbox Code Playgroud)

您可以看到1 destructed两者都没有101 destructed。我猜想像这样的类型std::Optional是以类似的方式实现的。


Ben*_*igt 7

不推荐,但这是另一种方式:

char buffer[sizeof(T) + alignof(T)];
char* aligned_buffer = buffer + alignof(T) - reinterpret_cast<intptr_t>(buffer) % alignof(T);
T* object = new (aligned_buffer) T;
Run Code Online (Sandbox Code Playgroud)

但是,虽然这意味着编译器不会自动调用析构函数,但程序员仍然可以:

object->~T();
Run Code Online (Sandbox Code Playgroud)

当然,堆分配也是如此:

delete object;
Run Code Online (Sandbox Code Playgroud)

为了防止这种情况,你必须使析构函数不可访问:

struct T
{
private:
   ~T() {};
};
Run Code Online (Sandbox Code Playgroud)

或者真的无法访问(相关:为什么只有在声明自定义构造函数时才能访问基类析构函数?):

class indestructible_base
{
    ~indestructible_base();
};

struct T : indestructible_base
{
};
Run Code Online (Sandbox Code Playgroud)

  • OMG,有人写了这个静态缓冲区黑客*并正确对齐对象*。我不敢相信这发生了。+1。 (3认同)