c++static-allocation

Pointer to array Maintain counter of elements


I have an interface which multiple classes inheritance.

    class someInterface
    {
        virtual void someMethod() = 0;
    }
    class A : public someInterface
    {
        public:
            void someMethod()
            {
                //Do something
            }
    }

    class B : public someInterface
    {
        public:
            void someMethod()
            {
                //Do something
            }
    }

    class C : public someInterface
    {
        public:
            void someMethod()
            {
                //Do something
            }
    }

For each of the classes A, B, C i have created an array with different sizes of their actual type inside a container class.

    class AContainer 
    {
        public:
            A As[10];
    }

    class BContainer 
    {
        public:
            B Bs[5];
    }
    etc...

Furthermore i have an array of pointers to "SomeInterface", where i want to have a pointer to each of the actual arrays like this.

    #define SOMEINTERRFACE_SIZE 3
    someInterface *array[SOMEINTERRFACE_SIZE];
    array[0] = AContainer.As; //Could also just be &AContainer.As[0]
    array[1] = BContainer.Bs;
    array[2] = CContainer.Cs;

    for (int i = 0; i < SOMEINTERRFACE_SIZE; ++i)
    {
        int elements = //Here i need a solution to get the size
                       //So i can iterate through the array, which the pointer points to.
        for (int i = 0; i < elements; ++i)
        {
            //Call the interface method on each element.
        }
    }

The problem occurs, when i have to use the someInterface array, since it isn't possible to get the size of the actual array through the someInterface pointer..

What is a good solution to this problem? I really need some help to solve this. Also don't want to use dynamic allocation, so no solution with vector<> or malloc etc. because I'm writing to an Arduino.


Solution

  • It won't work. In C++ you have to know the size of the elements in an array. A, B, and C might be different sizes, so you can't treat arrays of them the same.

    &AContainer.As[i] == &AContainer.As + i * sizeof(A)
    

    but

    &BContainer.Bs[i] == &BContainer.Bs + i * sizeof(B)
    

    So it's impossible for the same machine code to iterate over arrays of A and of B. If you want to iterate over an array of objects, you need to know the exact type.

    Remember in C++, if you want to get a polymorphic virtual call, you need to go through pointer or reference. The solution is to copy pointers to the elements in each array into one "master" array.

    SomeInterface *ptrs[NUM_A + NUM_B + NUM_C];
    SomeInterface **dest = ptrs;
    for (int i = 0; i < NUM_A; ++i) {
        *dest++ = &AContainer.As[i];
    }
    for (int i = 0; i < NUM_B; ++i) {
        *dest++ = &BContainer.Bs[i];
    }
    // et cetera...
    

    This only uses a little bit of extra space because you're storing pointers, not actual objects.

    EDIT: I guess you could do something like this if you really want to save the space:

    someInterface *arrays[] = { AContainer.As, BContainer.Bs, CContainer.Cs };
    int objSizes[] = { sizeof(A), sizeof(B), sizeof(C) };
    int arrLengths[] = { NUM_A, NUM_B, NUM_C };
    
    for (int j = 0; j < sizeof(arrays)/sizeof(arrays[0]); ++j)
    {
        void *ptr = arrays[j];
        for (int i = 0; i < arrLengths[j]; ++i) {
            someInterface *iptr = (someInterface *)ptr;
            iptr->method();
            ptr += objSizes[j];
        }
    }
    

    (this is untested, you might need to tweak a little.)

    In theory since all those arrays are full of compile-time constants, it should optimize out to something fast. If it doesn't, the code will run slower because it will be incrementing pointers by a value only known at runtime instead of compile time. You should check the assembly output if you really care about speed.