在下面的代码中,我们正在创建一个对象,绑定(bind)一个函数并在删除该对象之前调用它。
这显然会导致段错误,因为底层对象在删除后被使用。
在为异步数据提供回调的库上下文中,我们应该如何防止回调函数指向 nullptr
?
可以在cpp.sh/5ubbg上测试
#include <memory>
#include <functional>
#include <iostream>
class CallbackContainer {
public:
std::string data_;
CallbackContainer(std::string data): data_(data) {}
~CallbackContainer() {}
void rawTest(const std::string& some_data);
};
void CallbackContainer::rawTest(const std::string& some_data) {
std::cout << data_ << " " << some_data << std::endl;
}
int main(int /* argc */, char const** /* argv */) {
std::unique_ptr<CallbackContainer> container;
container.reset(new CallbackContainer("Internal data"));
auto callback = std::bind(&CallbackContainer::rawTest, container.get(), std::placeholders::_1);
callback("Before");
std::cout << &callback << std::endl;
container.reset();
std::cout << &callback << std::endl;
callback("After");
return 0;
}
返回:
> Internal data Before
> 0x7178a3bf6570
> 0x7178a3bf6570
> Error launching program (Segmentation fault)
最佳答案
如果您可以共享所有权,请执行以下操作:
int main(int /* argc */, char const** /* argv */) {
std::shared_ptr<CallbackContainer> container; // shared pointer
container.reset(new CallbackContainer("Internal data"));
// shared with functor
auto callback = std::bind(&CallbackContainer::rawTest, container, std::placeholders::_1);
callback("Before");
std::cout << &callback << std::endl;
container.reset();
std::cout << &callback << std::endl;
callback("After");
return 0;
}
如果不是,您应该以某种方式显式地将无效性传递给函数对象。 这假设您知道容器何时被删除,并在 之前手动明确地使其失效:
int main(int /* argc */, char const** /* argv */) {
std::unique_ptr<CallbackContainer> container;
container.reset(new CallbackContainer("Internal data"));
std::atomic<CallbackContainer*> container_raw(container.get());
auto callback = [&container_raw] (std::string data)
{
if (auto c = container_raw.load())
c->rawTest(data);
};
callback("Before");
std::cout << &callback << std::endl;
container_raw.store(nullptr);
container.reset();
std::cout << &callback << std::endl;
callback("After");
return 0;
}
对于asio情况,通常使用shared_from_this()
,比如std::bind(&MyClass::MyMemFunc, shared_from_this(), ptr);
关于c++ - 可以删除绑定(bind)函数时如何安全地使用回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61360300/