Organizing static data in C++

烈酒焚心 提交于 2019-12-14 03:52:31

问题


I'm working on some embedded software where there is some static information about "products". Since the information for a certain product never changes during execution I would like to initialize these data structures at compile time to save some space on the stack/heap.

I made a Product class for the data, intending to make a huge array of all the products in the system and then do lookups in this structure, but I haven't figured out quite how to get it working. The arrays are giving me loads of trouble. Some psuedo code:

class Product {
    int m_price;
    int m_availability[]; // invalid, need to set a size
    ... etc

    // Constructor grabbing values for all members
    Product(int p, int a[], ...);
}

static const Product products[] = 
{
    Product(99, {52,30,63, 49}, ...), // invalid syntax
    ...                    
}                     

Is there a way to making something like this work? The only thing I can think of would be to organize by attribute and skip the whole Product object. I feel that would make the whole thing harder to understand and maintain though.

Does anyone have any suggestions on how I might best organize this kind of data?

Thank you.


回答1:


An old school C style static array of structs sounds like a perfect match to your requirements. Initializes at compile time, zero runtime overhead, no use of stack or heap. It's not a co-incidence that C is still a major player in the embedded world.

So (one recipe - plenty of scope to change the details of this);

// in .h file
    class Product {
    public: // putting this first means the class is really a struct
        int m_price;
        int m_availability[4]; 
        //.... (more)
    };
    extern const Product product_array[];
    extern const int     product_array_nbr;

// in .cpp file
    const Product product_array[] =
    {
        {
             23,
             {56,1,2,4},
             //....(more)
        },
        {
             24,
             {65,1,2,4},
             //....(more)
        },
        //....(more)
    };

    const int product_array_nbr = sizeof(product_array)/sizeof(product_array[0]);



回答2:


A couple of years ago when I was working in embedded we needed to explicitly control the memory allocation of our structures.

Imagine this type of struct :

.h file

template<class T,uint16 u16Entries>
class CMemoryStruct
{
public:
    /**
    *Default c'tor needed for every template
    */
    CMemoryStruct(){};
    /**
    *Default d'tor
    */
    ~CMemoryStruct(){};
    /**
    *Array which hold u16Entries of T objects. It is defined by the two template parameters, T can be of any type
    */
    static T aoMemBlock[u16Entries];
    /**
    *Starting address of the above specified array used for fast freeing of allocated memory
    */
    static const void* pvStartAddress;
    /**
    *Ending address of the above specified array used for fast freeing of allocated memory
    */
    static const void* pvEndAddress;
    /**
    *Size of one T object in bytes used for determining the array to which the necessary method will be invoked
    */
    static const size_t sizeOfEntry;
    /**
    *Bitset of u16Entries which has the same size as the Array of the class and it is used to specify whether
    *a particular entry of the templated array is occupied or not
    */
    static std::bitset<u16Entries> oVacancy;
};


/**
*Define an array of Type[u16Entries]
*/
template<class Type,uint16 u16Entries> Type CMemoryStruct<Type,u16Entries>::aoMemBlock[u16Entries];
/**
*Define a const variable of a template class
*/
template<class Type,uint16 u16Entries> const void* CMemoryStruct<Type,u16Entries>::pvStartAddress=&CMemoryStruct<Type,u16Entries>::aoMemBlock[0];
template<class Type,uint16 u16Entries> const void* CMemoryStruct<Type,u16Entries>::pvEndAddress=&CMemoryStruct<Type,u16Entries>::aoMemBlock[u16Entries-1];
template<class Type,uint16 u16Entries> const size_t CMemoryStruct<Type,u16Entries>::sizeOfEntry=sizeof(Type);
/**
*Define a bitset inside a template class...
*/
template<class Type,uint16 u16Entries> std::bitset<u16Entries> CMemoryStruct<Type,u16Entries>::oVacancy;

Depending on your compiler and environment you could manipulate the area of where the static allocation take place. In our case we moved this to the ROM which was plenty. Also note that depending on your compiler i.e. Greenhills compilers, you may need to use the export keyword and define your static members to the .cpp file.

You can use the start and end pointers to navigate through the data. If your compiler supports full STL you may want to use std::vectors with custom allocators and overloaded new operators which would save your memory to somewhere else than the stack. In our case the new operators were overloaded in such a way that all the memory allocation was done on predefined memory structures.

Hope I gave you an idea.




回答3:


In C++98/03, you cannot initialize arrays in a constructor initializer.

In C++11, this has been fixed with uniform initialization:

class Product
{
  int m_availability[4]; 
public:
  Product() : m_availability{52,30,63, 49} { }
};

If you need the data to be provided in the constructor, use a vector instead:

class Product
{
  const std::vector<int> m_availability; 
public:
  Product(std::initializer_list<int> il) : m_availability(il) { }
};

Usage:

extern const Product p1({1,2,3});



回答4:


Memory for the static variables is still reserved when the code is actually executing -- you won't be saving space on the stack. You might want to consider use of vectors instead of arrays -- they're easier to pass and process.



来源:https://stackoverflow.com/questions/7535743/organizing-static-data-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!