【问题标题】:Fixed allocation std::vector固定分配 std::vector
【发布时间】:2019-07-08 12:25:08
【问题描述】:

我是一名嵌入式软件开发人员,因此我不能总是使用所有不错的 C++ 功能。最困难的事情之一是避免动态内存分配,因为它在某种程度上适用于所有 STL 容器。

std::vector 在处理可变数据集时非常有用。但问题是分配(例如std::reserve)不是在初始化时完成或固定的。这意味着在进行复制时可能会出现内存碎片。

最好让每个向量都有一个分配的内存空间,这是向量可以增长到的最大大小。这将创建确定性行为,并可以在编译时映射微控制器的内存使用情况。当向量达到最大大小时调用push_back 将创建一个std::bad_alloc

我读到可以编写std::allocator 的替代版本来创建新的分配行为。是否可以使用 std::allocator 创建这种行为,或者替代解决方案是否更合适?

我真的很想继续使用 STL 库并对其进行修改,而不是重新创建我自己的向量,因为与它们的实现相比,我更容易出错。

旁注 #1:

我不能将std::array 用作 1:它不是由我的编译器提供的,而 2:它确实具有静态分配,但我仍然必须管理 std::array 内的数据和缓冲区之间的边界.这意味着用我的分配属性重写std::vector,这是我想要摆脱的。

【问题讨论】:

  • 是什么阻止你在初始化时调用std::vector::reserve,你自己?
  • @SamVarshavchik 许多嵌入式系统甚至没有定义operator new。如果您在这些系统中调用动态分配函数,它将失败。 OTOH,有些确实有,但编码标准要求在启动时完成所有分配,在这种情况下.reserve() 将起作用。
  • @SamVarshavchik 这确实是我目前的解决方案但是以汽车为例:禁止动态分配,因为行为需要是确定性的。在集合空间内创建vector 可以解决这个问题。
  • 可以创建一个定制的分配器,它可以与标准容器一起使用,从内存池中分配内存。如果该内存池是在程序启动时分配的,那么程序启动后就不会重新分配。显然,有必要使用容器如何使用的知识来设计内存池本身,并在使用模式发生变化时相应地重新设计分配器(以及它如何管理内存池)。这是可能的,但并非微不足道 - 特别是如果您的开发人员希望任意调整标准容器的大小。
  • 我没有说数据隐藏意味着复杂性和更长的开发时间,我说 C++ 就是这个意思。原因是不可避免的代码膨胀、复杂性和元编程疯狂,几乎可以保证随之而来。它根本不是一种非常适合嵌入式系统开发的语言。如果你有纪律使用像 std::vector 这样的废话,那么你可以很好地使用 C++,但是具有不使用各种陷阱 C++ 特性的纪律的 C++ 程序员非常罕见。跨度>

标签: c++ embedded allocation


【解决方案1】:

你可以实现或重用boost的static_vector具有固定容量的可变大小数组容器。

【讨论】:

    【解决方案2】:

    您始终可以使用 C 样式数组(与 std::array 中的底层相同),因为向量不应该是静态的

    int arr[5]; // static array of 5 integers
    

    为了让它更有用,你可以将它包装在一个类模板中以隐藏 C 风格 示例:

    template<class type, std::size_t capacaty>
    class StaticVector {
        private:
            type arr[capacaty];
            std::size_t m_size;
        public:
            StaticVector() : m_size(0) {}
    
            type at(std::size_t index) {
                if (index >=0 && index < m_size) {
                    return arr[index];
                }
    
                return type();
            }
    
            void remove(std::size_t index) {
                if (index >=0 && index < m_size) {
                    for (std::size_t i=index; i < m_size-1; i++) {
                        arr[i] = arr[i+1];
                    }
                    m_size--;
                }
            }
    
            void push_back(type val) {
                if (m_size < capacaty) {
                    arr[m_size] = val;
                    m_size++;
                }
            }
    
            std::size_t size() {
                return m_size;
            }
    };
    

    使用示例:https://onlinegdb.com/BkBgSTlZH

    【讨论】:

    • 他说过new不是一个选项
    • 我想要托管类的 C++ 优点。回到 C 数组将是一大退步。另外我不想要一个静态大小的数组。我想要一个动态容器,它可以在静态内存空间内增长/缩小其暴露的接口。
    • onlinegdb.com/BkBgSTlZH 这是一个非常粗略的版本,以 C 样式为基础,但未公开,确实满足了您对“增长/收缩”的要求,无需在初始化时在特定静态中分配新内存和分配内存内存空间,但这确实需要您自己实现这些功能。
    • 或者...为此目的使用静态分配的链表。您在此处发布的代码速度非常慢,无法证明是合理的。 “我希望它像向量”不是一个合理的论点,“我想要快速代码”是。
    • 移动整个数组非常慢。这是一个幼稚的算法,链表的存在是有原因的。不过,您可以以更快的方式实现静态数组,将其用作环形缓冲区。同样,您可以将静态缓冲区用作链表。以此类推。
    猜你喜欢
    • 2012-07-04
    • 1970-01-01
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 2019-11-07
    • 1970-01-01
    相关资源
    最近更新 更多