如何通过unique_ptr调用包装对象的方法



我能够编译以下代码,其中我将"回调"传递给对象(表)。我现在要做的是在表中,调用事件侦听器中定义的句柄方法

#include <iostream>
#include <vector>
#include <memory>
class Table {
  public:
    struct Listener{ 
      virtual void handle(int i) = 0;
    };
    std::vector<std::unique_ptr<Listener>> listeners_;
    void add_listener(std::unique_ptr<Listener> l){
      listeners_.push_back(std::move(l));
    }
};

struct EventListener: public Table::Listener {
  void handle(int e){  
    std::cout << "Something happened! " << e << " n";
  }
};
int main(int argc, char** argv)
{
  Table table;
  std::unique_ptr<EventListener> el;
  table.add_listener(std::move(el));
  return 0;
}

编辑****

这就是我在表格中尝试的。它会导致分段错误:

for (auto t =0; t < (int)listeners_.size(); ++t) {
   listeners_[t]->handle(event); 
}

它不起作用,因为您从未创建过要调用的对象,只是一个指针。矢量内的指针将被nullptr,因此对其调用函数将崩溃。 unique_ptr与这个问题完全无关。

一半的问题是Table无法处理nullptr但不检查它,另一半问题是Table无法处理nullptr但无论如何main传递一个。

迭代代码根本不是问题。

正如小狗的回答中提到的那行

std::unique_ptr<EventListener> el;

创建一个空std::unique_ptr。这会导致代码侦听器稍后取消引用nullptr

示例的简单修复是创建一个侦听器并使用它创建unique_ptr时:

struct EventListener: public Table::Listener {
  void handle(int e){  
    std::cout << "Something happened! " << e << " n";
  }
};
// in main()
std::unique_ptr<NoOpListener> el{ new NoOpListener };
table.add_listener(std::move(el));

如注释中所述,您的代码应确保 nullptr是不允许的。一种方法是添加检查add_listener中的 nullptr 并引发异常或静默忽略他们。第一种选择是两者中更好的解决方案,因为它向调用方发出信号,指示有问题。

但我不明白你为什么要将听众存储在std::unique_ptr s中。std::unique_ptr的用途是所有权。我不明白为什么观察到的实例应拥有侦听器。还有另一种选择我认为更好;使用 std::function<>() 并按值传递它。这不允许使用nullptr,并具有接受的额外好处不仅是函数对象,还有普通函数和 lambda,如图所示在以下代码中:

#include <iostream>
#include <vector>
#include <memory>
#include <functional>
class Table {
  public:
    std::vector<std::function<void(int)>> listeners_;
    void add_listener(std::function<void(int)> l) {
      listeners_.push_back(l);
    }
    void invoke_listeners(int event)
    {
      for(auto l : listeners_) {
        l(event);
      }
    }
};

struct NoOpListener  {
  void operator() (int i) {
    std::cout << "NoOpListener::operator()(" << i << ")" << std::endl;
  }
};
void cb(int i) {
  std::cout << "cb(" << i << ")" << std::endl;
}
int main(int argc, char** argv)
{
  Table table;
  table.add_listener(NoOpListener{});
  table.add_listener(cb);
  table.add_listener([](int i) { std::cout << "[lambda](" << i << ")" << std::endl; });
  table.invoke_listeners(10);
  return 0;
}

注意:如您所见,我还使用了 C++11 ranged-for 构造进行迭代在听众之上。

相关内容

  • 没有找到相关文章

最新更新