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

时间:2014-11-29 14:23:37

标签: c++ smart-pointers unique-ptr

我能够编译以下代码,我将“回调”传递给对象(表)。我现在要做的就是在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); 
}

2 个答案:

答案 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构造进行迭代 听众。