静态分配继承对象的数组

问题描述 投票:2回答:4

这个问题的题目很复杂,所以我试着用一个例子来构思。比方说,我有一个抽象的基类,有许多继承自它的类。在下面的例子中,我只展示了两个继承的类,但实际上可能有更多的类。

class Base {
public:
  Base();
  virtual ~Base() = 0;
/// Other methods/members
};

class SmallChild: public Base {
public:
  SmallChild();
  ~SmallChild();
/// Other methods/members such that sizeof(SmallChild) < sizeof(LargeChild)
};

class LargeChild : public Base {
public:
  LargeChild();
  ~LargeChild();
/// Other methods/members such that sizeof(LargeChild) > sizeof(SmallChild)
};

我需要实现一个容器,该容器可以存储多达 N 继承的对象。这些对象需要在运行时创建-销毁,并放置在容器中,但由于项目的限制(特别是它是在嵌入式硬件上),动态内存分配不是一个选项。容器需要将所有的空间静态分配。另外,编译器不支持C++11。

我能想到的实现方法只有一个。要引用 N 对象,我首先需要创建一个指向基类的指针数组,然后为了实际存储这些对象,我需要创建一个足够大的缓冲区来存储 N 最大继承对象的副本,在本例中是 LargeChild

Base * children[N];
uint8_t childBuffer[N * sizeof(LargeChild)];

然后,我可以将指针分布在 children 横跨 childBuffer,各以 sizeof(LargeChild). 由于需要创建对象,可以使用C++的 "position new "将其放置在数组中的指定位置。我需要跟踪每个对象的类型,在 childBuffer 中的指针进行反引用。children但这应该不会太糟。

对于整个设置实施,我有几个问题。

  1. 这是解决我所描述的问题的好方法吗?我从来没有实施过类似的任何事情,所以我不知道我是否在这里吃午饭的方式,有一个更简单的方法来实现这个问题。

  2. 有多少是可以在编译时完成的?如果我有 M 继承类的类型(SmallChild, LargeChild等)但我 不要 知道了它们之间的大小关系,我怎么才能确定它们的大小呢?childBuffer? 这个大小取决于最大的类的大小,但有没有办法在编译时确定这个大小?我可以想象一些预处理器宏在类中迭代,评估 sizeof 并找到最大值,但我对这种级别的预处理器工作没有什么经验,也不知道这将是什么样子。我也可以想象使用模板可以做到这一点,但同样,我没有任何编译时模板巫术的经验,所以我只是基于我的直觉。如果有任何关于如何实现这个问题的指导,我将感激不尽。

c++ inheritance memory-management
4个回答
3
投票

你需要能够dealocate这些对象吗?如果不需要,可能会更容易地覆盖 operator new. 我指的是这个

void* operator new (std::size_t size) throw (std::bad_alloc);

你所有的覆盖都会从一个大的缓冲区中分配内存。要分配多少内存是由 size 副电表。

这样你应该可以直接说

children[i] = new SmallChild();

编辑:如果你确实需要deallocate,你需要更复杂的数据结构。反正最后你可能会重新实现堆。


0
投票

如果对象集是完全静态的(在构建时设置,在运行时不改变),通常的方法是使用每个派生类的一组数组,然后用指向其他数组的指针建立 "全局 "数组。

static SmallChild small_children[] = {
    { ...initializer for first small child... },
    { ...initializer for second small child... },
    ...
};
static LargeChild large_children[] = {
    { ...initializer for first large child... },
    ...
};
Base *children[N] = { &small_children[0], &small_children[1], &large_children[0], ....

如果经常有子类被添加和删除,或者子类数组的顺序很重要,那么这样的维护就会很棘手。 最好是用一个脚本或构建程序来生成上述源文件,该脚本或构建程序可以读取所需子程序的描述。


0
投票

考虑到你的约束条件(即不使用动态分配),你的方法很有意思。

事实上,你用你自己的方式管理了一个由以下几个元素组成的数组 union anyChild { smallChild o1; largeChild o2; ... };sizeof(anyChild) 会给你最大的块大小,你正在寻找。

顺便说一下,在你的方法中可能会有一个悬空指针的风险,只要所有的对象没有被创建为new,或者如果其中的一些对象通过显式调用它们的destructor被删除。


0
投票

如果你把你的派生类型放到一个联合体中。

    union Child{
        SmallChild asSmallChild;
        LargeChild asLargeChild;
    }

那么联合体将自动成为最大类型的大小。当然,现在你有一个新的问题。联合体中表示的是什么类型?你可以在基类中给自己一个提示,或者你可以把Child做成一个结构,其中包含一个提示,然后在里面内联。关于这个例子,请看githubs上Espressif为ESP32所做的组件,那里有很多很好的联合体用法。

总之,当你去分配时,如果你分配一个union'ed类型的数组,它将会生成一个最大的子数组......因为这就是union的作用。

© www.soinside.com 2019 - 2024. All rights reserved.