0

我正在尝试从 Java 中制作相当于事件侦听器,但在 C++ 中。我的目标是,我可以从一个类中调用一个函数,这会触发我添加到这个类中的监听器。

我找到了以下链接,它为我提供了解决方案。

特此的问题是,我的程序在我尝试调用侦听器时立即崩溃。

我的代码结构如下:

class MessageHandler abstract
{ 
public:
    typedef const std::function<void(int, std::string)> Handler;
    void addHandler(Handler& handler) {
            handlers.push_back(&handler);
    }
private:
    std::vector<Handler*> handlers;
protected:        
    void someFunction(int id, std::string message) {
        for (auto& handler : handlers) {
            (*handler)(id, message); //Here it will crash
        }
    }
};

正如您可能已经提到的,这是我从中派生一些子类的基类。然后这些子类调用我的“someFunction”代码。

我创建这些子类之一的类的结构如下:

class Server
{
private:
    SubHandler handler;

    void setHandlers() {
        handler.addHandler([&](int id, std::string message) { executingFunction(id, message); });
    }

    void executingFunction(int id, std::string message) {
        std::cout << "Listener Worked!" << std::endl;
        //Not actually the code inside, but it doesn't matter, case I don't even get to this code
    }
};

该程序在该行崩溃,我在其中循环我的侦听器并错误地调用它们:

“在位置 0x000000000000000010 读取时访问冲突。”

(这是翻译的,所以如果您将 Visual Studio 设置为英语,这不是您将收到的消息)

4

3 回答 3

1

您应该使用/permissive-. 编译器应该拒绝你的代码。

void addHandler(Handler& handler) {
        handlers.push_back(&handler);
}

你不应该能够向这个函数发送一个临时的,但你是!

//                 v----- This lambda is a temporary object --------------------------v
handler.addHandler([&](int id, std::string message) { executingFunction(id, message); });

在该行创建的 lambda 对象在语句完成后立即死亡。

//                 v---- pointer to the temporary.
handlers.push_back(&handler);

我的建议是删除指针并按std::function值使用对象。它们被设计成这样使用:

//  abstract is not a C++ keyword.
class MessageHandler /* abstract */
{ 
public:
    // using instead of typedef and non const
    using Handler = std::function<void(int, std::string)>;

    void addHandler(Handler const& handler) { // const reference
            // insert by value
            handlers.push_back(handler);
    }
private:
    // no pointer here.
    std::vector<Handler> handlers;
protected:        
    void someFunction(int id, std::string message) {
        for (auto const& handler : handlers) {
            handler(id, message); //Here it will not crash anymore
        }
    }
};
于 2019-03-27T19:41:40.783 回答
0

这是因为您在 Server 类方法中定义的 lambda 不在 MessageHandler 类的范围内。我建议您阅读以下内容:https ://blog.feabhas.com/2014/03/demystifying-c-lambdas/以了解问题所在以及如何解决。

不过,定义一个包含 lambda 的结构可能是一个很好的解决方案,然后它可以与std::mem_fn 一起使用。

希望这可以帮助

于 2019-03-27T18:56:46.207 回答
0

您的来源很糟糕:/您可能会改用以下内容:

class MessageHandler
{ 
public:
    using Handler = std::function<void(int, const std::string&)> Handler;

    void addHandler(const Handler& handler) { handlers.push_back(handler); }

    void execute(int id, const std::string& message) {
        for (auto& handler : handlers) {
            (*handler)(id, message);
        }
    }

private:
    std::vector<Handler> handlers;
};

然后使用它:

class Server
{
private:
    MessageHandler handler;

    void setHandlers()
    {
        handler.addHandler(&Server::executingFunction);
        handler.addHandler(
            [](int id, const std::string& message)
            {
                std::cout << message << id << std::endl;
            });
    }

    static void executingFunction(int id, const std::string& message) {
        std::cout << "Listener Worked!" << std::endl;
    }
};
于 2019-03-27T20:19:41.860 回答