以下代码是未定义的行为还是合法的?
#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.
}
问题是关于S::foo
已经启动并且保证位于不再访问this
指针的函数内部的指令的事实。此外,这个"foo()
内部的指令"受到内存围栏的保护(在我的示例中为std::mutex
(。if(b)
后面的代码也被隔离了(因为b
是std::atomic<bool>
(,对吧?
对我来说,返回到一个指针悬空的成员函数仍然有点可疑,但我找不到任何理由说明这应该是明确的"未定义行为"。它没有访问s->foo()
(因为函数已经启动(,并且在检查b
之后立即返回可以保证不会发生其他这种访问。
那么这是允许的吗是否纯粹是从子函数(在本例中为Wait(continueFoo)
(向一个成员函数返回,而该成员函数正悬挂着尚未定义的行为我在标准中找不到任何参考资料。
附言:这是我在Undefined behavior上第二次尝试删除";这个";当其他线程正在运行不访问"的成员函数时;这个";?。我认为这与链接的问题不同。C++中的这种未定义行为从悬挂指针调用函数是因为在s
删除后我没有取消引用它。我首先明确地调用s->foo
,然后删除实例(我保证线程已经启动(。
Richard Critten在评论中发布了正确的方向:
这个问题可以简化为:
struct foo { void bar() { delete this; /* what can I do here? */ } };
–Richard Critten">
delete this
是一个众所周知的现象,甚至在isocpp常见问题解答中明确回答:https://isocpp.org/wiki/faq/freestore-mgmt#delete-这个
因此,正确的答案基本上是:"是的,它已经定义好了。只要小心,好吗">