C++;保存在向量中的Lambda执行多次 我正在做一些C++的嵌入式程序库,我需要创建一个回调函数。我希望能够注册成员函数和lambda。我尝试了这个(简化的),但运气不好: #include <iostream> #include <functional> #include <vector> typedef const std::function<void (int)> connection_handler_t; std::vector<connection_handler_t*> connectionHandlerList; void addConnectionHandler(connection_handler_t& h) { connectionHandlerList.push_back(&h); } void runConnectionHandlers() { std::cout << "Running registered connection handlers" << std::endl; for (auto& handler : connectionHandlerList) { (*handler)(16); } } int main() { std::cout << "testing vector" << std::endl; addConnectionHandler([=](int i) { std::cout << "a: " << i << std::endl; }); addConnectionHandler([=](int i) { std::cout << "b: " << i << std::endl; }); runConnectionHandlers(); }

C++;保存在向量中的Lambda执行多次 我正在做一些C++的嵌入式程序库,我需要创建一个回调函数。我希望能够注册成员函数和lambda。我尝试了这个(简化的),但运气不好: #include <iostream> #include <functional> #include <vector> typedef const std::function<void (int)> connection_handler_t; std::vector<connection_handler_t*> connectionHandlerList; void addConnectionHandler(connection_handler_t& h) { connectionHandlerList.push_back(&h); } void runConnectionHandlers() { std::cout << "Running registered connection handlers" << std::endl; for (auto& handler : connectionHandlerList) { (*handler)(16); } } int main() { std::cout << "testing vector" << std::endl; addConnectionHandler([=](int i) { std::cout << "a: " << i << std::endl; }); addConnectionHandler([=](int i) { std::cout << "b: " << i << std::endl; }); runConnectionHandlers(); },c++,C++,我的预期结果是: testing vector Running registered connection handlers a: 16 b: 16 为什么它总是运行相同的lambda X次? 我正在为Java服务器开发客户机库,所以我是C语言的新手++ 谢谢这是因为显示的代码显示了未定义的行为。例如,使用我的编译器,我得到了您期望的结果,但这只是因为随机的机会 addConnectionHandler([=](int i) { std::cout << "a: " <

我的预期结果是:

testing vector
Running registered connection handlers
a: 16
b: 16
为什么它总是运行相同的lambda X次? 我正在为Java服务器开发客户机库,所以我是C语言的新手++


谢谢

这是因为显示的代码显示了未定义的行为。例如,使用我的编译器,我得到了您期望的结果,但这只是因为随机的机会

addConnectionHandler([=](int i) {
    std::cout << "a: " << i << std::endl;
});
这将在向量中保存指向传入对象的指针

不幸的是,正如我所解释的,传入的对象是一个临时对象,一旦这个函数返回,它就会被销毁。保存的指针指向已销毁的对象

下面的代码尝试使用保存的指针取消引用并调用类型擦除的lambda。但是,由于这些指针悬空,并且指向一个被破坏的对象,这将导致未定义的行为。每次调用程序时,您可能会看到不同的行为,甚至崩溃


这里不需要使用指针。只需创建一个包含
std::function
对象的向量,然后将输入的
std::function
按原样直接推入向量。在这个用例中不需要指针。

这是因为显示的代码表现出未定义的行为。例如,使用我的编译器,我得到了您期望的结果,但这只是因为随机的机会

addConnectionHandler([=](int i) {
    std::cout << "a: " << i << std::endl;
});
这将在向量中保存指向传入对象的指针

不幸的是,正如我所解释的,传入的对象是一个临时对象,一旦这个函数返回,它就会被销毁。保存的指针指向已销毁的对象

下面的代码尝试使用保存的指针取消引用并调用类型擦除的lambda。但是,由于这些指针悬空,并且指向一个被破坏的对象,这将导致未定义的行为。每次调用程序时,您可能会看到不同的行为,甚至崩溃


这里不需要使用指针。只需创建一个包含
std::function
对象的向量,然后将输入的
std::function
按原样直接推入向量。在这个用例中不需要指针。

我同意@SamVarshavchik的评论,但考虑到这不是您的实际代码,我将尝试推测并给出一些建议

使用指向临时对象的指针很可能会导致第一个“回调”指针指向与第二个“回调”实例化位置完全相同的位置,因为第一个“回调”不再使用

因此,如果你:

  • 使用
    连接处理程序的向量,而不是指向它们的指针
  • 向后放置
    或插入这些处理程序,而不是插入指向它们的指针
  • 你至少应该远离你所描述的。事实上,不管你看到什么样的行为,你都应该这样做

    附言:

    • 不要使用全局变量,你很可能真的需要它。如果您确实使用它,请注意并发访问它
    • 不要把事物的向量称为“事物列表”——它不是列表

    我同意@SamVarshavchik的评论,但考虑到这不是您的实际代码,我将尝试推测并给出一些建议

    很可能,使用指向临时对象的指针会导致第一个“回调”指针指向第二个“回调”实例化的完全相同的位置——因为第一个指针不再使用

    因此,如果你:

  • 使用
    连接处理程序的向量,而不是指向它们的指针
  • 向后放置
    或插入这些处理程序,而不是插入指向它们的指针
  • 你至少应该远离你所描述的。事实上,不管你看到什么样的行为,你都应该这样做

    附言:

    • 不要使用全局变量,你很可能真的需要它。如果您确实使用它,请注意并发访问它
    • 不要把事物的向量称为“事物列表”——它不是列表

    为什么要使用指向
    std::function
    的指针?您应该按原样使用
    std::function
    。您的错误是由于编译器创建了两个临时
    std:::function
    对象,这些对象是通过指针添加到
    vector
    的,而这些对象恰好在调用堆栈上使用了相同的内存地址。为什么要使用指向
    std::function
    的指针?您应该按原样使用
    std::function
    。您的错误是由于编译器创建了两个临时
    std:::function
    对象,您正在通过指针将它们添加到
    vector
    ,而这些对象恰好在调用堆栈上使用了相同的内存地址。您好,您的回答也很好。我稍微编辑了一下代码。我在实际代码中使用了类变量。这只是对问题的一种快速炫耀。谢谢你对vector vs list的评论。你好,你的答案也不错。我稍微编辑了一下代码。我在实际代码中使用了类变量。这只是对问题的一种快速炫耀。感谢您对vector vs list的评论。
    connectionHandlerList.push_back(&h);