【问题标题】:Moving std::function with member function使用成员函数移动 std::function
【发布时间】:2015-11-24 10:51:54
【问题描述】:

我使用std::function 编写了一个超级简单的事件系统。

相当于

std::vector<Delegate<Args ...>*> _delegates;

其中Delegatestd::function 的别名

template <typename ... Args>
using Delegate = std::function<void(Args ...)>;

事件的operator()operator+=operator-= 过载。

operator() calls all of the listening functions.
operator+= adds a listener.
operator-= removes a listener.

将它们连接起来看起来像这样......

Foo::Foo(Bar& bar)
{
    ...

    m_bar_ptr = &bar;

    using namespace std::placeholders;

    event_receiver =
    Delegate<const Bar&, const SomeBarData>
    (std::bind(&Foo::OnEventReceived, this, _1, _2));
    bar.BarEvent += event_receiver;

    ...
}

一切都按预期工作,但是当我移动 Delegate 的所有者时,我最终不得不取消挂钩并复制初始挂钩的代码(如预期的那样)。

看起来像这样……

Foo& Foo::operator=(Foo&& other)
{
    ...

    m_bar_ptr = other.m_bar_ptr;
    other.m_bar_ptr = nullptr;

    m_bar_ptr->BarEvent -= other.event_receiver;

    using namespace std::place_holders;

    event_receiver =
    Delegate<const Bar&, const SomeBarData>
    (std::bind(&Foo::OnEventReceived, this, _1, _2));
    bar.BarEvent += event_receiver;

    ...
}

除了必须保留 Bar 的句柄(这是可以接受的)之外,还有很多代码可以重新定位 Delegate...并留下很大的错误空间。

我喜欢这些事件的简单性(尽管我愿意接受建议),但我真正想要的是一种保持这个事件系统并简化动作的方法。

有什么建议吗?

谢谢

【问题讨论】:

  • 你为什么使用指向std::function的原始指针向量?
  • 因为std::functions 无法比较是否相等。我将它们存储在std::vector 中,并且需要能够找到它们以进行删除并避免添加重复项。

标签: c++ c++11 std move std-function


【解决方案1】:

在我看来,您似乎没有正确使用移动分配,除了创建副本之外没有移动任何东西。 event_receiver 是从头开始创建的,不会被移动。

我知道编写移动函数很诱人,认为它会自动提高效率。 但是在编写这样的函数时,效率是通过有效地移动对象成员来获得的。

在您的情况下,我认为您可以简单地使用复制分配并让 dtor 进行注销,或者更改移动功能以移动对象成员。

【讨论】:

  • 在这种情况下,在移动过程中,Foo 只是创建了一个新的Delegate(它非常轻量级,只是一个std::function),但 Foo 本身可能是一个大对象,可以从中受益移动。
猜你喜欢
  • 1970-01-01
  • 2023-03-31
  • 2015-03-04
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多