Boost.SML - 违反内存保护/分段错误

Boost.SML - Violation of memory protection/Segmentation fault

本文关键字:分段 错误 内存保护 SML Boost      更新时间:2023-10-16

程序返回"分段错误(核心转储)"。怎么了?

该实现基于示例 - "嵌套"表单文档 BOOST。SML:

http://boost-experimental.github.io/sml/examples/index.html#nested

SM 用于从服务器调用方法。服务器用于切换 SM 中的状态。

#include <boost/sml.hpp>
#include <iostream>
namespace sml = boost::sml;
using namespace std;
template <class = class Dummy>
class Server
{
struct pollEvent{};
struct msgRcdEvent{};
class States
{
public:
 States(Server *server): _server(server){}
auto operator()() const noexcept
{
  auto msgRcdAction = [this] {
  std::cout << "HB server -> msgRcdAction " << std::endl;
 _server->recvMsg();
};
auto pollAction = [this] {
 std::cout << "HB server -> pollAction " << std::endl;
  _server->poll();
};
using namespace sml;
return make_transition_table(
 *"idle"_s + event<pollEvent> / pollAction    = "Poll"_s,
 "Poll"_s + event<msgRcdEvent> / msgRcdAction = "RcdMsg"_s,
 "RcdMsg"_s + event<pollEvent> / pollAction   = "Poll"_s
);
}
private:
 Server *_server{nullptr};
};
public:
 Server()
 {
  _states = new States(this);
  _sm     = new sml::sm<States>(*_states);
 }
 void process(){_sm->process_event(pollEvent{});}
 void poll(){_sm->process_event(msgRcdEvent{});}
 void recvMsg(){_sm->process_event(pollEvent{});}
private:
 States *_states{nullptr};
 sml::sm<States> *_sm{nullptr};
};
int main()
{
 Server<> s{};
 s.process();
 return 0;
}

分段错误是由堆栈溢出引起的。因为_sm->process_event(...)是递归调用的。该函数立即处理事件。

为了避免它,我们需要一些排队事件机制的东西,而不是立即处理事件。

SML 提供它。

这是代码。请参阅评论1至3。

#include <boost/sml.hpp>
#include <iostream>
#include <queue>
namespace sml = boost::sml;
using namespace std;
template <class = class Dummy>
class Server
{
    struct pollEvent{};
    struct msgRcdEvent{};
    class States
    {
    public:
        States(Server *server): _server(server){}
        auto operator()() const noexcept
        {
            auto msgRcdAction =
                // 2. Add parameters to lambda expression
                //    The second parameter is process callable object that is from
                //    action. The template argument `pollEvent` is the event you want
                //    to pass to the `process`.
                //    You can write multiple template arguments.
                //    e.g.) sml::back::process<pollEvent, msgRcdEvent>
                [this] (auto const& /*ev*/, sml::back::process<pollEvent> process) {
                    std::cout << "HB server -> msgRcdAction " << std::endl;
                    _server->recvMsg(process);
                };
            auto pollAction =
                [this] (auto const& /*ev*/, sml::back::process<msgRcdEvent> process) {
                    std::cout << "HB server -> pollAction " << std::endl;
                    _server->poll(process);
                };
            using namespace sml;
            return make_transition_table(
                *"idle"_s + event<pollEvent> / pollAction    = "Poll"_s,
                "Poll"_s + event<msgRcdEvent> / msgRcdAction = "RcdMsg"_s,
                "RcdMsg"_s + event<pollEvent> / pollAction   = "Poll"_s
            );
        }
    private:
        Server *_server{nullptr};
    };
public:
    Server()
    {
        _states = new States(this);
        _sm     = new sml::sm<States, sml::process_queue<std::queue>>(*_states);
    }
    void process1(){_sm->process_event(pollEvent{});}
    // 3. Invoke process callable object
    template <typename Process>
    void poll(Process p){ p(msgRcdEvent{});}
    template <typename Process>
    void recvMsg(Process p){ p(pollEvent{});}
private:
    States *_states{nullptr};
    // 1. Add `sml::process_queue<std::queue>` template argument to `sml::sm`.
    sml::sm<States, sml::process_queue<std::queue>> *_sm{nullptr};
};
int main()
{
    Server<> s{};
    s.process1();
    return 0;
}

sml::back::process<pollEvent>(注释 2)是将事件排队的可调用(类似函数)的对象。您可以调用它而不是_sm->process_event(...)(注释 3)。队列设置为sm的模板参数(注释 1)。