c++arraysdesign-patternsenums

Enum and Array vs Separate Variables to store multiple instances of a class


The following is a toy example:

An image stores a width, height and filepath, represented by the struct IMAGE:

#include <cstdlib>
#include <type_traits>
struct IMAGE {
    int WIDTH;
    int HIGHT;
    const char* FILEPATH;
};
static_assert(std::is_pod<IMAGE>::value);

There are a 100 unique IMAGEs in a game such as a Dirt Block, a Sword, and a Main Menu etc. One approach (1) to storing all these 100 images in a program is to use separate variables for each unique image:

int main(){
    IMAGE DIRTBLOCK = IMAGE(25, 25, "RESOURCE\\DIRTBLOCKIMAGE");
    IMAGE SWORD = IMAGE(100, 25, "RESOURCE\\SWORDIMAGE");
    IMAGE MAINMENU = IMAGE(500, 500, "RESOURCE\\MAINMENUIMAGE);
}

Another approach (2) could be to use an enum of Image Names and an array of IMAGEs:

enum IMAGENAME : unsigned char {
    DIRTBLOCK,
    SWORD,
    MAINMENU,
    NUMIMAGES
};

IMAGE* IMAGES; 

int main(){
    IMAGES = (IMAGE*)std::malloc(sizeof(IMAGE) * NUMIMAGES);
    IMAGES[DIRTBLOCK] = IMAGE {25, 25, "RESOURCE\\DIRTBLOCKIMAGE"};
    IMAGES[SWORD] = IMAGE {100, 25, "RESOURCE\\SWORDIMAGE"};
    IMAGES[MAINMENU] = IMAGE {500, 500, "RESOURCE\\MAINMENUIMAGE"};
    std::free(IMAGES);
}

Generally, What are the advantages and disadvantages of approaches (1), (2). Alternatively, is there a better approach(3), I have not considered.

I am relatively new to c++, so your help is appreciated.


Solution

  • I came up with a solution based on the suggestion of Ted Lyngmo. I'm not expecting reputation points for this. I only want to show timmy george a possible solution in reasonable C++. Live code.

    The container used is an unordered_map. The IMAGENAME enum is the key, and IMAGEs are the value. The container can be walked directly with a range-for or a standard for with the addition of the increment() increasing the value of the enum iterator. Care must be taken not to exceed the range of the enum.

    My additional comment is to break from C naming and use a C++ convention. I would change IMAGENAME to ImageName and IMAGE to Image. Similarly, rename the enums to DirtBlock and the member fields to mWidth. In short, stop shouting in your code. LOL

    #include <print>
    #include <unordered_map>
    using std::println, std::print;
    
    enum IMAGENAME : unsigned char { DIRTBLOCK, SWORD, MAINMENU, NUMIMAGES, LASTIMAGE };
    
    void increment(IMAGENAME& in) {
       in = static_cast<IMAGENAME>(static_cast<int>(in) + 1);
    }
    struct IMAGE {
        int WIDTH;
        int HEIGHT;
        const char* FILEPATH;
    };
    
    std::unordered_map<IMAGENAME, IMAGE> images{
        {DIRTBLOCK, IMAGE{25, 25, "RESOURCE\\DIRTBLOCKIMAGE"}},
        {SWORD, IMAGE{25, 25, "RESOURCE\\SWORDIMAGE"}},
        {MAINMENU, IMAGE{25, 25, "RESOURCE\\MAINMENUIMAGE"}},
    };
    
    auto main() -> int {
        for (auto const& image : images) {
            println("{}", image.second.FILEPATH);
        }
        println("");
    
    
       for (IMAGENAME in{}; in != NUMIMAGES; increment(in)) {
          println("{}", images.at(in).FILEPATH);
       }
    
        return 0;
    }