Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Best way to allocate memory pool at compile time

32 views
Skip to first unread message

bitrex

unread,
Jul 4, 2016, 10:12:27 AM7/4/16
to
I'm working on writing my own little event-driven scheduler for a
microprocessor in C++, as both a learning exercise for C++ and something
that might have some practical use for me down the road.

So I have an abstract class called "AbstractEvent" that the different
types of user-defined events can derive from. The subclasses are
templated with string designators and a class data package that can be
templated to store different kinds of data provided by the event
generator, which a particular "observer" might require.

Since this is for a uP with no MMU, all buffers and required objects are
sized and instantiated at compile time and then not touched via
placement new, etc.

The idea is that there will be a static memory pool of different event
types which _can_ be dispatched, and a memory pool of events which have
been dispatched that are waiting for consumption by the receivers. When
a new event is generated a new "data package" is created, the required
event type is copy-constructed from the static pool, the new package
placed in its buffer, and the event placed alongside the other events
waiting to be processed in a container within a "state object."

Since the subclasses of the abstract type are templated, the ideal way
to do this would be to instantiate a unique_ptr for each subclass and
store the unique_ptrs in a vector. Unfortunately the stlib available for
this processor doesn't implement all C++11 features, even though the
compiler is C++11 compatible.

I've decided that the simplest workaround is to just store the
dispatched events in a regular ol' pre-allocated array buffer and then
have a vector of base pointers to the event objects for the rest of the
code to work with. But that means that I need to know the largest size
of all the event classes the user wants to work with to size the cells
appropriately.

So essentially what I'm asking is that say in the setup code the user
wants an "Event<int, foo>" (where "foo" is a string designator), an
"Event<char, bar>", and an Event<float, baz>". Since the types of the
subclasses of AbstractEvent required by a specific implementation are
all known at compile time, I'm wondering if there's a way that I can
have a memory pool generated at compile time for them, with cells large
enough to hold any subclass instance, such that the compiler will inform
me how much data memory is used by the pool (it's a Harvard architecture
uP.) Instead of having the pool instantiated at runtime.

If there's a better way to go about this I'm open to suggestions as
well. Thanks.

Alf P. Steinbach

unread,
Jul 4, 2016, 10:30:01 AM7/4/16
to
On 04.07.2016 16:12, bitrex wrote:
>
> [snip]
> So essentially what I'm asking is that say in the setup code the user
> wants an "Event<int, foo>" (where "foo" is a string designator), an
> "Event<char, bar>", and an Event<float, baz>". Since the types of the
> subclasses of AbstractEvent required by a specific implementation are
> all known at compile time, I'm wondering if there's a way that I can
> have a memory pool generated at compile time for them, with cells large
> enough to hold any subclass instance, such that the compiler will inform
> me how much data memory is used by the pool (it's a Harvard architecture
> uP.) Instead of having the pool instantiated at runtime.
>
> If there's a better way to go about this I'm open to suggestions as
> well. Thanks.

You could use Boost solution, but since this is a microprocessor with a
limited compiler you may not have Boost available. And anyway, with a
Boost dependency the code may need to be updated every third year or so
just in order to still compile. I used to love Boost but it's big and
hairy, it has at least two competing date-time sub libraries neither of
which is up to my standard of usability, and it's forever changing.

For the DIY C++ has two mechanisms for generating a "cell" that can hold
any of N specific types:

* an array of bytes used via placement new and support for alignment, and

* a union.

The union (keyword) is nice but there is no direct support for a
/discriminated union/, a union where there is a member that specifies
the main type stored in there, like a Pascal variant record.

One way is to store a pointer to dummy polymorphic type representative.
This approach leverages default generated copying for the union, while
supporting dynamic_cast, which is nice. In the other direction, if you
find that client code is frequently discriminating on type then that's a
common anti-pattern, something to avoid; it's so bad that it was the
main reason why Bertrand Meyers did not include enumerations in Eiffel.

Cheers & hth.,

- Alf

0 new messages