【发布时间】:2019-12-21 11:43:23
【问题描述】:
我有一个类,它在std::function 中存储回调并执行一些操作,然后将结果通知回调目标。如果目标看到结果无效或不想继续工作,它将删除包含std::function 回调的调用者类。
我知道如果std::function 在删除后不访问其成员,这将是安全的,但我没有看到这样的保证。我的事情是调用者类在调用回调后不会访问其成员,但是回调可以选择再次做更多的工作,在这种情况下它不会删除调用者。
这个例子说明了这个问题:
using callback = std::function<void(Caller& c, bool failed)>;
class Caller
{
callback cb;
bool Work()
{
return true;
}
public:
Caller(const callback& cb) : cb{ cb } {}
void DoWork()
{
bool result = Work();
cb(*this, result);
}
};
int main(int argc, char **argv)
{
for (int i = 0; i < 1000; ++i)
{
Caller *c = new Caller{
[](Caller& c, bool failed)
{
if (failed)
delete &c;
else
c.DoWork();
}
};
c->DoWork();
}
}
我使用 msvc 在 windows 上编译了代码,它可以正常工作(或者可能是一些隐藏的堆损坏?)
我不希望建议使用另一种设计,因为我使用的真实代码很复杂,调用者类就像工作人员和回调之间的一个 proky,并且是按操作分配的,重构代码也会很多工作
编辑:我知道这不是最好的 c++ 实践,但我正在处理 c api 特别是 iocp。我的代码是这样工作的:io 对象(套接字)发出一个 io 请求,需要为重叠的结构和操作数据分配内存,这个结构将保存回调,当操作完成时,它将调用回调,如果有错误回调可能不会继续,否则它将发出下一个请求。调用回调后,结构将自行删除,从回调开始的新操作将像这样继续。
现在假设我有一个半双工协议的会话,比如 http,那么一次只有一个操作,所以我可以对所有操作使用相同的结构而无需再次分配,所以当第二个操作开始时我破坏了旧结构并在适当位置构造新结构,这是在第一个结构的回调中完成的
【问题讨论】:
-
这里为什么不用shared_ptr?这样您就不必删除任何内容。
-
这能回答你的问题吗? Is delete this allowed? 我认为这相当于
delete &c;应该与delete this;相同 -
即使它不是 UB 而是操作代码 - 你也不应该这样做。您多次违反 C++ 准则。你最好现在就做额外的工作和重构,而不是继续以这种方式编写代码并创建一个更大的难以管理的可憎。
标签: c++ memory-management