c++ - 可以删除绑定(bind)函数时如何安全地使用回调

标签 c++ c++11 callback

在下面的代码中,我们正在创建一个对象,绑定(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/

相关文章:

具有共享对象的 C++11 多线程

javascript - TypeScript 中的 Mongoose 方法范围

c++ - c++ 类的 objective-c 链接器错误

c++ - 如何专门化依赖于类的静态数据成员的模板?

C++双指针数组列表

c++ - Eric Niebler 的 std::is_function 实现如何工作?

c++ - 访问 CALLBACK 函数中的对象字段 (WINAPI - C++)

methods - 有什么方法可以让构建器使用创建对象的方法注册回调?

c++ - 如何将 double 转换为整数

c++位操作如何打印出16、32位