离开范围后如何保护局部变量的值?
How to protect a value of a local variable after leaving scope?
我将 C 库的subscribe
函数包装到更高级别的 C++ 类方法中。在该方法中,底层 Csubscribe
被调用,并带有一个作为引用传入的局部char*
变量 (char key[10]
(。现在的问题是 - 我刚刚弄清楚 - 因为key
是一个局部变量,其值不受保护。我可以传递它的引用,但是一旦范围离开,该内存将可用。我正在经历这种undefined
回调行为永远不会被调用 - 调试后我看到key
的值被更改了。
我尝试使用似乎有效的new char[10]
。但我想这不是我应该去的路。
正确的解决方案是什么?更新:现在通过替换为string
来修复它。
更新
接口功能:
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData)
包装纸:
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(key); // error, exit
callback(json);
}
);
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
包装器的主要任务:
{
...
aws->subscribe(
topic,
[&] (const std::string &json) -> void {
ESP_LOGI(TAG, "got json: %s", json.c_str());
}
);
...
}
更新 #2
c_style_callback
中的回调 lambda 无法访问正确的callback
和key
值。如何保护这 2 个不被覆盖?将它们"包裹"在unique_ptr
内?将task
返回给呼叫者以供参考?此外,帮助程序的返回值get_pvoid()
指向用户数据,即lambda函数,也许应该受到保护?
执行此操作的方法是在堆上分配内存(new
,malloc
(。您有以下几种选择:
- 首选:如果
new
内存,可以将指针包装成std::unique_ptr
或std::shared_ptr
,并安全地传递。当最后一个实例超出范围时,内存会自动释放。可以通过get()
直接访问指针。你必须确保没有其他人释放你的记忆! - 使用 RAII(资源获取即初始化(包装器类型,该包装器类型执行
malloc
和free
,或new
和delete
。在这种情况下,通过构造函数分配内存,并通过析构函数释放内存,同时将原始指针传递给 C 接口。缺点是您必须实现复制/移动语义以确保不会发布两次,并且正确跟踪存储此指针的所有副本。由于这涉及的复杂性,如果可以的话,我建议您使用unique/shared_ptr
。也可以 将自定义删除器传递给shared_ptr
,因此您也可以将其与free
一起使用作为删除器。 - 您可以使用新的原始指针,但必须确保只删除一次。
相关文章:
- 使用的未初始化局部变量'Quick'
- 修复未初始化的局部变量错误
- 局部变量保留函数中的值
- 如何使用 C++ 中的继承函数访问派生类中的局部变量
- 将引用分配给局部变量,如果局部变量超出范围,它会超出范围吗?
- Gnuplot_i.hpp C++接口绘制局部变量而不是文件
- 如何在函数外部访问函数中局部变量的值?
- 赋予全局变量而不是局部变量优先级的函数 - (异常行为)
- C++中静态方法的局部变量范围
- 未初始化的局部变量错误甚至认为我初始化了它(C++)
- 离开范围后如何保护局部变量的值?
- 局部变量名称冲突
- C++ lambda:如何'freeze'局部变量的值?
- 我应该使我的局部变量常量还是可移动的
- 获取具有静态局部变量的绑定/推断捕获 lambda 的函数指针
- 全局和局部变量初始化与 constexpr 的差异背后的基本原理
- 返回对局部变量 - C++ 的引用
- 是否可以影响 C++ 中回调函数的局部变量?
- 警告 C4101 未引用的局部变量
- 线程局部变量的初始化顺序