2
\$\begingroup\$

I want to have some classes that would contain arrays of different sizes. I want this to be statically allocated because it is intended for an embedded system. The only good solution I can think of is using templates.

However, I want to use the same class type to access those objects.

This is my solution so far.

class Base
{
public:
    Base(char* _data, int _size) :
        data(_data), size(_size) {}

    char* getData(void)
    {
        return data;
    }

    int getSize(void)
    {
        return size;
    }

protected:
    char* const data;
    const int size;
};

template <int sz>
class Foo : public Base
{
public:
    Foo() : Base(dataBuff, sizeof(dataBuff)) {}
private:
    char dataBuff[sz];
};

// Here I can access every template that inherits Base class
void printFoo(Base* base)
{
    std::cout << base->getData() << std::endl;
    std::cout << "size is " << base->getSize() << std::endl;
}

int main(void)
{
    Foo<20> foo;

    char* data = foo.getData();
    strcpy(data, "Hello world");
    printFoo(&foo);
    return 0;
}

Of course the reason for this is to have more methods in the base class for appending deleting and searching for data.

Is this something valid? This is something very basic.
Can I have a better solution?

EDIT: Fixed bug (typo).

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Why not use std::array? If that's not available in your embedded environment, then perhaps it is better to reimpkement it, so you can write array<char, 20> foo; \$\endgroup\$ Commented Nov 29, 2022 at 11:27
  • \$\begingroup\$ @G.Sliepen I have to check if std::array is suitable without adding too much overhead (program memory, RAM etc..). I'll look at it for sure! Thank you for your comment! \$\endgroup\$ Commented Nov 29, 2022 at 11:57
  • \$\begingroup\$ std::array will add space to the current scope (so no dynamic memory allocation). While std::vector gives you dynamic memory allocation. \$\endgroup\$ Commented Nov 29, 2022 at 18:00
  • 1
    \$\begingroup\$ PS. This is broken. The compiler told you it was broken and you cast away the error. (char*)& dataBuff: Don't use C cast it says I know better than the compiler (which is usually not the case). It gets rid of your error message but the problem is still there. \$\endgroup\$ Commented Nov 29, 2022 at 18:02
  • \$\begingroup\$ @MartinYork That was a mistake! Thank you for pointing out! Fixed it. \$\endgroup\$ Commented Nov 30, 2022 at 16:38

1 Answer 1

1
\$\begingroup\$

Use std::array if possible

You can get a statically allocated buffer using std::array. Its implementation is very similar to your Foo, with the added benefit that it works like any other STL container. Here is how you would use it:

#include <array>
#include <cstring>
#include <iostream>

int main()
{
    std::array<char, 20> foo;
    strcpy(foo.data(), "Hello world");
    std::cout << foo.data() << "\nSize is " << foo.size() << '\n';
}

About static allocation

In your example, foo is not allocated statically, rather it is allocated on the stack. You could prepend static in front of it and/or declare that variable outside a function to ensure it is really allocated statically.

Then the question is whether this will save you any memory. Many embedded systems do allow dynamic allocation of heap memory. Sure, there is some overhead associated with it, but an advantage is that you only allocate as much as you need, whereas with an array of a static size, you might have to reserve more memory than you are going to need. What is best depends on the situation.

About type erasure

However, I want to use the same class type to access those objects.

I don't see a reason for that in your example usage. But if you do need to pass something like a pointer to Base along, consider that you don't need inheritance; you can have a separate class that stores a pointer to the array and a size, like std::span for arrays, or std::string_view for strings in particular. Here is an example using std::span that matches your example:

#include <array>
#include <cstring>
#include <iostream>
#include <span>

void printFoo(std::span<char> base)
{
    std::cout << base.data() << "\nSize is " << base.size() << '\n';
}

int main()
{
    std::array<char, 20> foo;
    strcpy(foo.data(), "Hello world");
    printFoo(foo);
}

If you cannot use std::array and/or std::span on your embedded system, I recommend you try to implement them yourself. Your code already has parts of it, you just need some name changes and to not use the span as a base class for the array anymore.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.