0

I have a use case where I've to create a map of function pointers and use it across various files. I've written the code for the template in a header file, along with the code to fill the map. When I don't define map as static, I get an error saying multiple definitions of the map because I include this header into multiple cpp files. To avoid that, I created map as static. However, now the program fails with Seg Fault probably because map is not yet initialized when I started adding the functions. How can I solve this problem?

Header file -

#ifndef KEY_COMPARE__H
#define KEY_COMPARE__H

#include <map>

enum DataType {
    A,
    B,
    MaxType
};

static const int MAX_KEYS = 5;

typedef bool (*Comparator)(uint8*, uint8*);
static std::map<long, Comparator> ComparatorMap; // <--- This is the map

template<typename T, typename... Args>
long GetComparatorKey(T first, Args... args) {
    // Code to return a unique key based on first, args...
}

template <int N, DataType T, DataType... Ts>
struct Comparator {

    Comparator() {
        long comparatorKey = GetComparatorKey(T, Ts...);
        ComparatorMap[comparatorKey] = c1Func; // Seg fault here
    }

    static bool Compare(uint8 *rec1, uint8 *rec2){
        // Function to compare
    }

    static const size_t nKeys_ = Comparator<N+1, T, Ts...>::nKeys_ - 1;
    Comparator<N+1, A, T, Ts...> ci_;
    Comparator<N+1, B, T, Ts...> cs_;

    bool (*c1Func)(uint8*, uint8*) = Compare;
};

/// Other code for base cases and stop recursion

#endif // KEY_COMPARE__H

Edit:

I've also tried to create a struct with map as static member variable to avoid global variables. Even that doesn't seem to work.

Sashank
  • 590
  • 7
  • 22
  • 1
    This if going to sound odd, but `KEY_COMPARE__H` is an illegal identifier. More on that at [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – user4581301 Dec 07 '18 at 06:25

1 Answers1

3

When you define a variable as static that means internal linkage, which makes it kind of private to each translation unit.

I.e. each source file will have its own unique and distinct instance of the map.

To make the map global and shared between all translation units, just declare the map (using extern instead of static). And in a single source define the map (without static or extern).

And note that global variables are usually discouraged.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • But I'm populating the map in the header file. If I define the map somewhere else, how can I make sure that's defined before it's populated? Won't I run into the same seg fault error again? – Sashank Dec 07 '18 at 05:48
  • @Sashank You populate it in the *class*, but you do not *initialize* the map (beyond construction). And unless you create an instance of the `Comparator` class globally, then the map is guaranteed to have been constructed first (global variables will be constructed before the `main` function is called). – Some programmer dude Dec 07 '18 at 06:17
  • @Sashank However there are some other things with your code and question that needs clarification. Like your use of multiple `Comparator` symbols for different types. And the fact that you get a seg-fault when you really should not get any, which indicate that you *do* construct `Comparator` objects before the map is constructed (smelling of [static initialization order fiasco](https://isocpp.org/wiki/faq/ctors#static-init-order)). I answered as good as I could with the information provided, which is clearly to little. Please create an [mcve] to show us! – Some programmer dude Dec 07 '18 at 06:20