我使用ESP-32,需要使用FreeRTOS队列传递std::shared_ptr
。但是,它失去了一个链接。我认为这是问题的根源:
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
}
class testClass {
public:
testClass() {
std::cout << "Class is constructed" << std::endl;
};
virtual ~testClass() {
std::cout << "Class is destructed" << std::endl;
};
};
struct container {
std::shared_ptr<testClass> field;
};
extern "C" void app_main(void) {
auto queue = xQueueCreate(1, sizeof(container));
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p); // 1
{
container c;
c.field = p;
PRINT_USE_COUNT(p); // 2
xQueueSendToBack(queue, &c, 0);
PRINT_USE_COUNT(p); // 2
}
PRINT_USE_COUNT(p); // 1 (Ooops!)
{
container c;
assert(xQueueReceive(queue, &c, 0) == pdTRUE);
PRINT_USE_COUNT(c.field); // 1
}
// Class is destructed
std::cout << "Test finished" << std::endl;
vQueueDelete(queue);
}
因此队列中有一个指针,但是不计入指针!
我该如何解决此问题(并尽可能使用FreeRTOS队列)?使用std::move
无济于事。
答案 0 :(得分:2)
仅当std::is_trivial<T>::value
为true(主要是POD或可复制对象)时,C风格的原始指针队列才适用于C ++ shared_ptr。
由于存在memcpy和其他普通的C操作操纵内存,因此引用计数将无法正确处理(因为它是C代码在幕后,并且不会调用析构函数),因此您可能会得到一个内存泄漏。
没有简单的方法可以解决此问题,但是最好的方法是自己管理内存。
答案 1 :(得分:0)
我并不总是同意从头开发一些东西是最好的选择。在大多数情况下,使用经过充分测试的东西可能是最佳选择——尽管它可能需要进行一些调整才能满足您的需求。
通过队列,您可以传递动态创建的容器实例。使用队列将数据从一个任务发送到同一个任务是非常罕见的,如果有的话,如上例所示。我不太喜欢在嵌入式 CPU 中使用动态分配,开销有时会影响性能。
下面是一个工作 PoC,其中传递了一个指向新容器实例的指针,而不是原始副本。在这种方法中,接收任务有责任释放实例以避免内存泄漏。
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
}
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
class testClass {
public:
testClass() {
std::cout << "testClass constructed" << std::endl;
}
~testClass() {
std::cout << "testClass destructed" << std::endl;
}
};
class myContainer {
public:
myContainer(std::shared_ptr<testClass> p) {
_p = p;
std::cout << "myContainer constructed" << std::endl;
}
~myContainer() {
std::cout << "myContainer destructed" << std::endl;
}
std::shared_ptr<testClass>& p() {
return _p;
}
private:
std::shared_ptr<testClass> _p;
};
extern "C" void app_main(void) {
std::cout << "Start of test, creating the shared_ptr..." << std::endl;
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p);
std::cout << "Creating one container..." << std::endl;
myContainer c(p);
PRINT_USE_COUNT(p);
std::cout << "Creating the queue..." << std::endl;
auto q = xQueueCreate(1, sizeof(myContainer*));
std::cout << "Sending a dynamically created item to the queue..."
<< std::endl;
myContainer *cp = new myContainer(p);
xQueueSendToBack(q, &cp, 0);
PRINT_USE_COUNT(p);
{
myContainer *pc;
xQueueReceive(q, &pc, 0);
PRINT_USE_COUNT(p);
std::cout << "Use count of pc->p() " << pc->p().use_count()
<< std::endl;
std::cout << "Freeing the dynamically created item..." << std::endl;
delete pc;
PRINT_USE_COUNT(p);
}
std::cout << "end of test" << std::endl;
}
这是程序的输出:
<块引用>开始测试,创建 shared_ptr...
构建的测试类
使用次数:1
正在创建一个容器...
myContainer 已构建
使用次数:2
正在创建队列...
将动态创建的项目发送到队列...
myContainer 已构建
使用次数:3
使用次数:3
使用 pc->p() 3 的次数
释放动态创建的项目...
myContainer 被破坏
使用次数:2
测试结束
myContainer 被破坏
testClass 被破坏