首页 > 解决方案 > 是否从等待返回到悬空的“this”实例的未定义​​行为?

问题描述

以下代码是未定义的行为还是合法的?

#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是 a std::atomic<bool>),对吧?

对我来说,返回到 this 指针悬空的成员函数仍然感觉有点可疑,但我找不到任何理由说明这应该是明确的“未定义行为”。它没有访问s->foo()(因为函数已经启动)并且在检查后立即返回以b保证不会发生其他 this 访问。

那么这是允许的吗?是否纯粹子函数(Wait(continueFoo)在这种情况下)返回到成员函数,其 this 悬空已经未定义的行为?我在标准中找不到任何参考。

PS:这是我在未定义行为( Undefined behavior)中第二次尝试在其他线程运行不访问“this”的成员函数时删除“this”的问题?. 我不认为它与链接的问题相同。C++ 中的这种未定义行为是否从悬空指针调用函数,因为在删除它后我没有取消引用s。我明确地首先调用s->foo然后删除实例(并且我保证线程已经启动)。

标签: c++thread-safety

解决方案


Richard Critten 在评论中发布了正确的方向:

问题可以简化为:

struct foo { void bar() { delete this; /* what can I do here? */ } };

——理查德·克里顿”

delete this是一个众所周知的现象,甚至在 isocpp 常见问题解答中明确回答:https ://isocpp.org/wiki/faq/freestore-mgmt#delete-this

所以正确的答案基本上是:“是的,它的定义。小心点,好吗?”


推荐阅读