我能够编译以下代码,我将“回调”传递给对象(表)。我现在要做的就是在Table中,调用 EventListener
中定义的句柄方法#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;
}
编辑****
这就是我在Table里面尝试的内容。它会导致分段错误:
for (auto t =0; t < (int)listeners_.size(); ++t) {
listeners_[t]->handle(event);
}
答案 0 :(得分:1)
它不起作用,因为你从来没有创建一个对象来调用它,只是一个指针。向量内的指针将为nullptr
,因此调用其上的函数将崩溃。 unique_ptr
与此问题完全无关。
问题的一半是Table
无法处理nullptr
但不检查它,另一半问题是Table
无法处理nullptr
但{ {1}}无论如何都会传递一个。
迭代代码根本不是问题。
答案 1 :(得分:0)
正如Puppy的回答中提到的那样
std::unique_ptr<EventListener> el;
创建一个空的std::unique_ptr
。这导致代码用于nivoking
听众以后取消引用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
中。
std::unique_ptr
的用途是用于所有权。我不明白为什么
观察实例应该拥有监听器。还有另一种选择
我认为更好;使用std::function<>()
并按值传递它。
这不允许使用nullptr
并且还有额外的接受奖励
不仅是函数对象,还有正常函数和lambdas,如图所示
在以下代码中:
#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构造进行迭代 听众。