为什么捕获 lambda 不捕获变量?
Why capturing lambda does not capture variables?
我不明白为什么传递给c_style_callback
的回调lambda无法访问callback
和key
的正确值。如何从 lambda 获得这 2 个?
我尝试使用显式复制[callback=callback, key=key]
,没有帮助。
这是一个名为subscribe
的 C 方法的C++包装器实现。
我认为以下代码涵盖了我的问题,如果需要其他内容,请告诉我。
包装器,问题位于此处。请检查行尾的评论:
std::function<void()> AWS::subscribe(const std::string &topic, std::function<void(const std::string&)> callback, QoS qos) {
ESP_LOGI(TAG, "subscribe: %s", topic.c_str());
std::string key("Test...");
auto task = c_style_callback(
[=] (AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, IoT_Publish_Message_Params *params) {
std::string json;
json.assign((char *)params->payload, (size_t)params->payloadLen);
ESP_LOGI(TAG, "subscribe cb payload=%s", json.c_str()); // works
ESP_LOGI(TAG, "key '%s'", key.c_str()); // undefined behaviour
callback(json);// error, exit
}
);
m_error = ::aws_iot_mqtt_subscribe(
&m_client,
key.c_str(),
key.length(),
qos,
task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>(),
task.get_pvoid()
);
if (m_error != SUCCESS) {
ESP_LOGD(TAG, "subscribe: error=%d", m_error);
return nullptr;
}
return [=] () {
ESP_LOGI(TAG, "unsubscribe %s", key.c_str()); // works
callback(key); // works
};
} // subscribe
c_style_callback
实用功能:
template<class F>
struct c_style_callback_t {
F f;
template<class...Args>
static void(*get_callback())(Args..., void*) {
return [](Args...args, void* fptr)->void {
(*static_cast<F*>(fptr))(std::forward<Args>(args)...);
};
}
void* get_pvoid() {
return std::addressof(f);
}
};
template<class F>
c_style_callback_t< std::decay_t<F> >
c_style_callback( F&& f ) { return {std::forward<F>(f)}; }
调用subscribe
包装器的主要任务 - 这只是为了给示例提供上下文,我如何尝试使用subscribe
的 C++ 包装器:
{
...
aws->subscribe(
topic,
[] (const std::string &json) -> void {
ESP_LOGI(TAG, "got json: %s", json.c_str());
}
);
...
}
更新:
更多关于aws_iot_mqtt_subscribe
:
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
* @param pApplicationHandlerData Data to be passed as argument to the application handler callback
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);
我假设aws_iot_mqtt_subscribe
存储其参数以供以后引用 - 调用函数,以响应稍后某个时间点的某个事件,函数作为其倒数第二个参数传递,指针作为其最后一个参数传递。
使用task.get_pvoid()
获得的指针指向task
的数据成员。反过来,task
是一个局部变量 - 当subscribe
与其数据成员一起返回时,它被销毁,因此指针变得悬空。
稍后,c_style_callback_t::get_callback
制造的函数接收到该不再有效的指针并尝试取消引用它。因此,程序通过在其生存期结束后访问对象来表现出未定义的行为。
相关文章:
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 在 lambda 捕获中声明的变量的类型推导
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 在 C++ 中访问 lambda 捕获初始化变量
- Visual C++: MSVC vs. GCC+CLANG: 处理 lambda 捕获类成员变量,正确的方法是什么?
- 作为模板变量的 Lambda
- 变量不在 lambda 的范围内
- 为什么 lambda 采用变量的初始值
- 为什么捕获 lambda 不捕获变量?
- C++ lambda:如何'freeze'局部变量的值?
- 获取具有静态局部变量的绑定/推断捕获 lambda 的函数指针
- Simulink "Access Violation"写入 C++ lambda 函数捕获列表中的 PWork 变量
- C++使用 lambda 初始化变量
- 如何在 lambda 表达式中传递变量?
- C++将 lambda 函数另存为成员变量,而不使用函数指针进行优化
- C++ lambda - 捕获静态成员变量
- 当使用lambda进行变量的复杂初始化时,如何处理从内部抛出的lambda外部异常
- 无法通过引用捕获 lambda 中的成员变量
- 是否允许在作为静态数据结构成员的lambda函数中捕获变量
- C 递归变量lambda