2

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

  #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";

我只是在这种“工作”中很幸运(因为它是未定义的行为)还是在信号2中有一些魔术指针计数阻止我把脚吹走?

4

1 回答 1

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

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

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

信号2中是否有一些魔术指针计数阻止我把脚吹掉?

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

与显示的代码无关:

您当然可以通过使用 things 在您自己的实体上拥有相同的功能std::vector<shared_ptr<Foo> >。如果对元素的引用/迭代器foos需要稳定,请使用std::liststd::deque(只有前/后插入/删除)。

这是我对通过 UBsan/ASan 的代码的看法,无论是否经过优化:

住在科利鲁

#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
于 2022-01-15T17:13:22.120 回答