Question

I am developing a library that will consist of header files only. So far, it contains only classes, which has been fine. However, I have come to a point where I need to have some library-wide accessible unchanging data in the library (that is, not class instance data) for the implementation of some functions. You obviously can't just put global data in header files, or else every compilation unit that #includes the header will have a definition for the symbol and you'll get multiple definition errors at link-time.

I seem to have found a workaround that lets me have static data in a class without having to add a compilation unit to the library by just making the data a static variable in a function and returning a pointer to that data:

class StaticData {
public:
    void doSomething() { /* this uses getData */ }
    void doSomethingElse() { /* this does too */ }

private:
    static int* getData() {
        static int array[] { 1, 2, 3, 4 };

        return array;
    }
};

This appears to be working fine, but I must admit that I don't know what happens to function-static data in inline functions in header files. I am wondering if this "hack" has any unintended repercussions, such as every compilation unit that #includes this header getting its own version of array. How and where does the compiler decide to put it?

Also it should be noted that I am not using this to implement the singleton antipattern or anything. I am just using it to store data that multiple functions will need to use (which is why it can't be static in just a function that uses it, but even if it did, that would prompt the same question).

Was it helpful?

Solution

That's fine. It's guaranteed that there will only be one copy of array, as long as the function has external linkage, which this does. The C++ standard says:

7.1.2/4 A static local variable in an extern inline function always refers to the same object.

OTHER TIPS

Another approach...

template<typename> class ArrayData {
    friend class ClassWithArray;
    static int array[4];
};

class ClassWithArray :
    ArrayData<ClassWithArray>
{
public:
    void doSomething() { 
        /* this uses getData */ 
        array[0] = 1;
        array[1] = 2;
        array[2] = 3;
        array[3] = 4;
    }
    void doSomethingElse() { 
        /* this does too */ 
        array[0] = 4;
        array[1] = 3;
        array[2] = 2;
        array[3] = 1;
    }
};

int ArrayData<ClassWithArray>::array[4] = { 1, 2, 3, 4 };

generic implementation

template<typename T> class ArrayDataT 
{
    friend T;
    static int array[4];
};

template<typename T>
int ArrayDataT<T>::array[4] = { 1, 2, 3 ,4 };

class DerivedFromArrayDataT :
    ArrayDataT<DerivedFromArrayDataT>
{

};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top