告诉编译器不要在我的 __thread 变量上执行析构函数

Eri*_*tch 0 c++ gcc clang

我特别希望我的变量之一没有构造函数和析构函数。它的定义是这样的

struct Dummy { ~Dummy() { assert(0); } };
__thread Dummy dumb;
Run Code Online (Sandbox Code Playgroud)

真正的代码是零初始化的,并从线程本地内存池中获取内存。该池在 main 末尾被销毁,因此该析构函数尝试访问已释放的内存池。

我可以解决这个问题,但我想以一种干净的方式做到这一点。1)我可以告诉编译器在所有线程本地(或全局)变量之后释放我的池吗?或者是否在所有线程本地函数之前对其进行初始化,以便在适当的时间进行清理?或者更好的是 2) 根本不执行清理?我本可以发誓__thread不允许构造函数/析构函数,所以我很惊讶这甚至运行了。

堆栈跟踪显示__run_exit_handlers是调用析构函数的函数。它的父母是exit__libc_start_main并且start。这在 clang 和 gcc 上都会发生

小智 7

在我给出答案之前,任何读到这篇文章的人都应该知道这通常是一个非常糟糕的主意,应该被视为最后的手段。然而,OP想要的是可行的,所以这里是:

析构函数可能是 C++ 语言中最可靠的东西。因此,如果你想阻止一个对象被执行,你就必须自己管理对象的生命周期和内存。

我们可以只使用new对象Dummy而不是delete它,但这会泄漏堆内存,这是不可取的。相反,我们希望创建但不销毁Dummy内存中与线程本地对象本身关联的对象。

为此,要走的路是std::aligned_storageplacement new

struct Dummy { ~Dummy() { assert(0); } };

struct DummyWrapper {
  DummyWrapper() {
    // Create the dummy
    dummy_ptr = new (&dummy_data) Dummy();
  }

  // Intentionally leave the destructor defaulted-out
  ~DummyWrapper() = default;

  operator Dummy&() { return *dummy_ptr; }

  std::aligned_storage_t<sizeof(Dummy), alignof(Dummy)> dummy_data;
  Dummy* dummy_ptr;
};

__thread DummyWrapper dumb;
Run Code Online (Sandbox Code Playgroud)

DummyWrapper对象将被构造和销毁,这是无法避免的。然而,该Dummy对象只会被创建,而不会被销毁,但底层内存管理仍然保持正常。