Is the following code undefined behaviour or legal?
#include <thread>
#include <functional>
#include <atomic>
std::atomic<bool> b{false};
// these are defined in some other file.
// actual implementation is not important for this question here
Handle insideFoo, continueFoo; // some type defined somewhere
void Wait(Handle h); // blocks current thread until someone calls Continue(h)
void Continue(Handle h); // makes any thread blocked in Wait(h) continue
struct S {
int i;
void foo() {
i = 23; // <- sample code that uses "this" pointer
Continue(insideFoo); // <- signal main that we are inside S::foo and past all "this" usage
Wait(continueFoo); // <- block until main tells us to continue
// here, "this" is destroyed (see main function)
if (b) return; // <- b is not instance variable, so its not an access to dangling "this"
i = 42; // <- other sample code that uses "this" pointer
}
};
int main() {
S* s = new S;
continueFoo.lock();
std::thread t(std::bind(&S::foo, s));
Wait(insideFoo); // wait until S::foo is finished accessing "this"
delete s;
b = false;
Continue(continueFoo); // let s.foo continue.
}
The question is about the fact that S::foo
already started and is guaranteed to be at an instruction inside the function that does not access the this
pointer anymore. Also, this "instruction inside foo()
" is protected by a memory fence (std::mutex
in my example here). The code that follows if(b)
is also fenced (by the fact that b
is a std::atomic<bool>
), right?
To me, it still feels kind of fishy to return to a member function whose this-pointer is dangling, but I can't find any reason why this should be explicitly "undefined behaviour". Its not accessing s->foo()
(because the function already started) and the immediate return after the check to b
guarantees that no other this-access happens.
So is this allowed? Is purely returning from a subfunction (Wait(continueFoo)
in this case) into a member-function whose this is dangling already undefined behaviour? I could not find any reference in the standard to that.
PS: This is a second attempt on my (poorly explained) question at Undefined behaviour to delete "this" when other thread is running member function that does not access "this"?. I don't think its the same question as the linked Is this undefined behaviour in C++ calling a function from a dangling pointer because I am not dereferencing s
after its deleted. I am explicitly first calling s->foo
and then deleting the instance (and I guarantee that the thread already started).