从回调中删除调用信号 boost::signals c++

Deleting calling signal from callback boost::signals c++

我有以下代码在信号回调之一期间删除信号:

  #include <iostream>
  #include <boost/signals2/signal.hpp>

  struct Foo {
    boost::signals2::signal<void(int)> signal;
  };

  std::vector<Foo> foos;
  foos.emplace_back(Foo());

  std::vector<int> values;
  auto connection = boost::signals2::scoped_connection(foos[0].signal.connect([&](int x) {
    foos.clear(); // delete the foos here, where we will be calling from below
    values.emplace_back(1);
  }));

  foos[0].signal(1);
  std::cout << "values.size()=" << values.size() << "\n";

我只是在这个“工作”中很幸运(因为它是未定义的行为)还是在 signals2 中有一些魔法指针在阻止我吹走我的脚?

 // delete the foos here, where we will be calling from below

这是误导性评论。删除 (clear()) 仅在 发出信号后 发生,因此控制流与代码行的顺序相反。

对我来说,这段代码看起来有效,除非你从信号处理程序中破坏 connection(例如 connection.release();)。即使这样,它 也可能 是安全的,但这取决于处理程序迭代的实现细节。我怀疑它仍然没问题,因为 Signals2 库是明确的线程感知的,所以反过来一定没问题(在信号调用期间将处理程序添加到同一个槽)。

is there some magic pointer counting in signals2 that is stopping me from blowing my feet off?

Signals2 中神奇的引用计数是您已经拥有的位:scoped_connection,当最后一个副本超出范围时,它将自动断开连接。

Not really related to the code shown:

You can of course have the same facility on your own entities, by using things std::vector<shared_ptr<Foo> >. If the references/iterators to elements of foos need to be stable, use std::list or std::deque (with only front/back insertion/removals).

这是我对通过 UBsan/ASan 优化和未优化的代码的看法:

Live On Coliru

#include <boost/signals2/signal.hpp>
#include <iostream>

namespace s2 = boost::signals2;

struct Foo {
    s2::signal<void(int)> onEvent;
};

int main() {
    std::vector<Foo> foos(3);

    std::vector<int> values;
    std::cout << "before values.size()=" << values.size() << "\n";

    s2::scoped_connection connection =
        foos.back().onEvent.connect([&](int x) {
            foos.clear(); // delete the foos here
            values.emplace_back(1);
            connection.release();
        });

    foos.back().onEvent(1);
    std::cout << "after values.size()=" << values.size() << "\n";
}

版画

before values.size()=0
after values.size()=1