嵌入式系统的C++数据容器

Ram*_*ich 5 c++ embedded stl data-structures cortex-m

我使用嵌入式系统.通常这意味着我有一个小型微控制器,具有64 - 512 KB的RAM和128 - 1024 KB的闪存,如STM32.我更喜欢使用C++来编程这样的系统.但我还没有找到可接受的方法来处理常见的数据结构,如堆栈,队列,地图等.

当然,STL具有所有这些以及许多其他方便的东西,但是大多数STL容器需要支持异常和动态内存分配,这在嵌入式编程中通常是不合需要的.

我知道我们可以通过使用自定义分配器来避免这个问题,我们可以从静态对象池或类似的东西中分配内存.然而,我看到的主要问题是,当没有足够的分配空间将新元素插入容器时,我们无法可靠地处理这种情况.STL和我见过的其他类似stl的库提出了两个选择:

  • 断言.这意味着当分配空间不足时系统会失败.
  • 回调.好一点,但对我来说还不方便.

    q.push(newElem); /* fails or just calls predefined callback
                      * when not enough space in queue.
                      */
    
    Run Code Online (Sandbox Code Playgroud)

也许我错了.但在我看来,最好的方法是返回状态,通知调用者它没有足够的内存容器中的新元素.我想自己决定如何处理这个错误.例如,我想删除新元素,向调试日志发送消息并恢复正常的程序流.从我的角度看,它看起来更可靠.

换句话说,我想有这样的事情:

queue<uint32_t, 128> q;
// some code ... 
queue::status sts = q.push(newElem);
if (sts != queue::OK)
    LOG("Not enough space in queue\r\n");

// continue normal program execution ...
Run Code Online (Sandbox Code Playgroud)

有人建议如何处理那件事?

nat*_*ate 1

您可以使用自定义分配器,在空间不足时抛出 std::bad_alloc,然后在代码中包装取决于异常处理块中插入成功的部分,并在 catch 子句中处理分配失败。

std::queue <message> Queue;

try
{
  Queue.insert (message {"hello world"});
}
catch (std::bad_alloc const & Error)
{
  LOG (Error.what ());
}
Run Code Online (Sandbox Code Playgroud)

对于简单的场景,这有点冗长,只要小心(使用 RAII)它可以是一个强大的工具。此外,如果您分配了这些简单的场景,则可以在模板中隐藏此模式。

template <typename fn>
void log_failure_and_contiue (fn Fn)
{
    try
    {
      Fn ();
    }
    catch (std::bad_alloc const & Error)
    {
      LOG (Error.what ());
    }
}

std::queue <message> Queue;

log_failure_and_continue ([&] {
  Queue.insert ({ "Hello World!" });
});
Run Code Online (Sandbox Code Playgroud)

从性能角度来看,大多数编译器都实现零成本异常处理,因此只有在抛出异常时才会受到影响,我认为在这种情况下这种情况应该很少见。

  • 异常会占用可执行二进制文件的很大空间。数百KB。因此,在闪存大小可能为 128 KB 或更小的嵌入式系统中,这通常是不可接受的。 (4认同)