https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118854
--- Comment #16 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Jonathan Wakely from comment #11) > https://en.cppreference.com/w/cpp/language/multithread#Data_races Please read this link, carefully. "Two expression evaluations conflict if one of them modifies a memory location or starts/ends the lifetime of an object in a memory location, and the other one reads or modifies the same memory location or starts/ends the lifetime of an object occupying storage that overlaps with the memory location." One of your threads ends the lifetime of an object (pInstance) at a memory lcoation, and the other thread reads the same memory location. So the two expressions conflict. "A program that has two conflicting evaluations has a data race unless - both evaluations execute on the same thread or in the same signal handler, or" No, one is in the main thread, one is in the thread running the run() member. "- both conflicting evaluations are atomic operations (see std::atomic), or" They're not. "- one of the conflicting evaluations happens-before another (see std::memory_order)." They don't, because there is no synchronization ensuring that the copy of pInstance happens-before the destructor starts. None of these conditions are met, so a data race occurs. "If a data race occurs, the behavior of the program is undefined." Your program has undefined behaviour. It happens to exhibit as a use-after-free, but it could be any other form of misbehaviour. There is a bug in your program. If you ensure that the last copy of pInstance happens-before the destructor, by joining the background thread before pInstance is destroyed, then there will be no data race.