Reputation: 1029
In a system where dynamic memory allocation is not allowed (ie no use of std::vector etc), what is a good way to make a fixed sized buffer class without using templates?
A have noticed my executable size start to creep due to repeated code generation.
Currently I have a pattern similar to this, note that a Fifo is not necessarily the actual application, just a simplified example.
template <int S>
class FixedSizeFifo
{
private:
std::array<uint8_t, S> mBuf;
public:
PushFunction() {...}
PopFunction() {...}
};
FixedSizeFifo<1000> myTransmitFifo;
FixedSizeFifo<100> myReceiveFifo;
My first obvious solution was to allocate the storage first then pass a pointer and size into the Fifo class, but it makes for more initialisation code and management of pointers etc.
class FixedSizeFifo
{
private:
uint8_t * mBuf;
size_t mBufSize;
public:
FixedSizeFifo() = delete; // And other copy constructors/operators
FixedSizeFifo(uint8_t * buf, size_t s) : mBuf(buf), mBufSize(s) {}
PushFunction() {...}
PopFunction() {...}
};
std::array<uint8_t, 1000> txBuf;
auto myTransmitFifo = FixedSizeFifo(txBuf.data(), txBuf.size());
std::array<uint8_t, 100> rxBuf;
auto myReceiveFifo = FixedSizeFifo(rxBuf.data(), rxBuf.size());
What are other interesting techniques for fixed sized storage applications like this?
Thanks...
Upvotes: 2
Views: 613
Reputation: 1029
There are three common solutions to this type of problem. All have their pros and cons:
1 - Template the class/function you are passing to (as in the first example above). This runs the risk of code bloat depending on the number of template instantiations and complexity of the template class. Does make for clean and simple looking code though.
2 - Pass a pointer and size (as in the second example above) - Avoids templates completely but does add the risk of managing pointers, but those can usually be easily mitigated. Potentially compatible with C code.
3 - Use a similar design pattern to std::string_view (or etl::array_view in the Embedded Template Library) or std::span. Basically wrap a pointer to the allocated memory and its size in another object and pass that in. Has the advantages of being able to then call common functions on the passed in wrapper. However, you now have a third step in the calling code; create the memory, create the wrapper to the memory, call the function with the wrapper.
Upvotes: 1