I specifically want no constructors and no destructors on one of my variables. It's defined as this
struct Dummy { ~Dummy() { assert(0); } };
__thread Dummy dumb;
The real code is zero initialized and grabs memory out of the thread local memory pool. The pool is destroyed at the end of main so this destructor tries to access a freed memory pool.
I can work around the problem but I wanted to do this in a clean way. 1) Can I tell the compiler to free my pool after all thread local (or global) variables? Or have it initialized before all thread local functions so it's cleaned up at the proper time? Or better yet 2) Not execute the cleanup at all? I could have sworn __thread
doesn't allow constructors/destructors so I was surprised this even ran.
The stack trace shows __run_exit_handlers
being the function that calls the destructor. It parents are exit
, __libc_start_main
and start
. This occurs on both clang and gcc
CodePudding user response:
Before I get into the answer, anyone reading this should know that this is generally a very bad idea, and should be treated as a last resort. However, what the OP wants is feasible, so here it is:
Destructors are possibly the single most reliable thing in the C language. So if you want to prevent one from being executed, you'll have to manage the object's lifecycle and memory by yourself.
We could just new
the Dummy
object and never delete
it, but that would leak heap memory, which is not desirable. Instead, we want to create, but never destroy, the Dummy
object in the memory associated with the thread-local object itself.
For this, the way to go is std::aligned_storage
and placement 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<sizeof(Dummy), alignof(Dummy)> dummy_data;
Dummy* dummy_ptr;
};
__thread DummyWrapper dumb;
The DummyWrapper
object will be constructed and destroyed, there's no going around that. However, the Dummy
object is only ever created, and never destroyed, but the underlying memory management is still kept sane.