The initialization order of static variables is not defined so it depends on your particular setup, including compiler, linker and linking order.
The Initializer Function Trick
You can use the initializer function trick to ensure that something is initialized when needed. I know that this works for certain on Windows with Microsoft's C++ compiler (and did a little testing on g++ with Linux, see below).
Initializer Function
The first step is to move the map into a function as a static variable and always access the map through this function.
buttonmap_t& buttonMap() {
static buttonmap_t map;
return map;
}
Usage
The map is created when the buttonMap()
function is first called. If you access the map through the function then you can be sure that it will be created.
Controller::Button::Button(int type) :
type_(type) {
buttonMap()[type] = this;
}
The crucial part is the initialization of the global variable: you replace it with a reference and initialize it from the function that holds the variable.
buttonmap_t& map = buttonMap();
Explanation
With this setup the initialization order doesn't matter because the first call to the function will perform the initialization and every call after it will use the initialized instance.
Note: this trick works for global variables because the initialization phase is done on a single thread. Even if you don't know the exact order of initialization, you can be sure that it will happen sequentially.
Testing
I tested this on my home computer with g++ on Linux and it seems to work:
$ g++ main.cpp controller.cpp -Wall
$ ./a.out
running...
the final program:
// controller.h
#ifndef CONTROLLER_H
#define CONTROLLER_H
class Controller {
public:
class Button {
public:
Button(int type = -1);
private:
int type_;
};
Controller();
Button A;
Button B;
Button X;
Button Y;
};
#endif
// controller.cpp
#include "controller.h"
#include <map>
typedef std::map<int, Controller::Button*> buttonmap_t;
buttonmap_t& ButtonMap() {
static buttonmap_t map;
return map;
}
buttonmap_t& map = ButtonMap();
Controller::Controller() :
A(0),
B(1),
X(2),
Y(3) {
}
Controller::Button::Button(int type) :
type_(type) {
ButtonMap()[type] = this;
}
// main.cpp
#include "controller.h"
#include <iostream>
Controller controller;
int main(int argc, const char * argv[]) {
std::cout << "running..." << std::endl;
return 0;
}