一个围绕FreeRTOS队列的C++封装可以简化为以下内容:
问题显然出在`std::shared_ptr`上,因为它与`memcpy`根本不兼容,由于复制到队列时未调用其复制构造函数/赋值运算符,导致当事件消息(因此是shared_ptr)超出范围时,所持有的对象被过早地删除。
我可以通过使用动态分配的`T`实例并将队列更改为仅包含指向该实例的指针来解决这个问题,但我不想这样做,因为这将在嵌入式系统上运行,并且我非常希望在运行时保持内存静态。
我的当前计划是将队列更改为包含指向包装类中本地保留的内存区域的指针,在其中可以实现完整的C++对象复制,但是因为我还需要保护该内存区域免受多线程访问,这实际上破坏了已经线程安全的FreeRTOS队列实现(肯定比我自己编写的任何实现都更有效),我可能会跳过它们。
最后,问题是:
在我实现自己的队列之前,是否有任何技巧可以使FreeRTOS队列与C ++对象实例(特别是`std::shared_ptr`)一起使用?
template<typename T>
class Queue<T>
{
public:
bool push(const T& item)
{
return xQueueSendToBack(handle, &item, 0) == pdTRUE;
}
bool pop(T& target)
{
return xQueueReceive(handle, &target, 0) == pdTRUE;
}
private:
QueueHandle_t handle;
}
xQueueSendToBack
的文档说明:
该项通过复制而非引用进行排队。
不幸的是,它实际上是通过复制来完成的,因为最终都会使用memcpy
,这在C API中很有意义。虽然这对于普通数据很有效,但对于以下事件消息等更复杂的项目会带来严重问题。
class ConnectionStatusEvent
{
public:
ConnectionStatusEvent() = default;
ConnectionStatusEvent(std::shared_ptr<ISocket> sock)
: sock(sock)
{
}
const std::shared_ptr<ISocket>& get_socket() const
{
return sock;
}
private:
const std::shared_ptr<ISocket> sock;
bool connected;
};
问题显然出在`std::shared_ptr`上,因为它与`memcpy`根本不兼容,由于复制到队列时未调用其复制构造函数/赋值运算符,导致当事件消息(因此是shared_ptr)超出范围时,所持有的对象被过早地删除。
我可以通过使用动态分配的`T`实例并将队列更改为仅包含指向该实例的指针来解决这个问题,但我不想这样做,因为这将在嵌入式系统上运行,并且我非常希望在运行时保持内存静态。
我的当前计划是将队列更改为包含指向包装类中本地保留的内存区域的指针,在其中可以实现完整的C++对象复制,但是因为我还需要保护该内存区域免受多线程访问,这实际上破坏了已经线程安全的FreeRTOS队列实现(肯定比我自己编写的任何实现都更有效),我可能会跳过它们。
最后,问题是:
在我实现自己的队列之前,是否有任何技巧可以使FreeRTOS队列与C ++对象实例(特别是`std::shared_ptr`)一起使用?