I have a class called Controller
, inside of which, I have a class called Button
. A Controller
contains several Button
instances of different types (e.g. button_type_a
, button_type_b
).
controller.h
#ifndef __controller__
#define __controller__
class Controller
{
public:
class Button
{
public:
Button(int type = -1);
private:
int type;
};
Controller();
Button A;
Button B;
Button X;
Button Y;
};
#endif
The button types are int
s, and I would like to be able to associate certain button type int
s with pointers to Button
instances of those particular types.
To keep track of this association, I use a std::map<int, Controller::Button*>
, which I typedef
to a buttonmap_t
.
As I create new Button
instances (in the Controller
constructor), the Button
constructor registers the types of those Button
s with the map.
controller.cpp
#include "controller.h"
#include <map>
typedef std::map<int, Controller::Button*> buttonmap_t;
buttonmap_t map;
Controller::Controller() :
A(0),
B(1),
X(2),
Y(3)
{ }
Controller::Button::Button(int type) :
type(type)
{
map[type] = this;
}
Then I create a global Controller
object, and I define main()
.
main.cpp
#include <iostream>
#include "controller.h"
Controller controller;
int main(int argc, const char * argv[])
{
std::cout << "running..." << std::endl;
return 0;
}
Depending on the order in which I compile the sources, the program either runs fine, or triggers a segmentation fault:
apogee:MapTest$ gcc controller.cpp main.cpp -o maptest -lstdc++
apogee:MapTest$ ./maptest
running...
apogee:MapTest$ gcc main.cpp controller.cpp -o maptest -lstdc++
apogee:MapTest$ ./maptest
Segmentation fault: 11
It seems like the latter case is trying to use the map before it has been properly initialized, and that's causing a seg fault. When I debug with Xcode, the debugger stops in "__tree" as the std::map
is calling __insert_node_at()
, which throws EXC_BAD_ACCESS(code=1, address=0x0)
. The call stack reveals that this was triggered by the first Button
instance calling map[type] = this;
.
So, here's my multi-part question:
int
to Button*
mapping that is unaffected by
compile order?Ideally, I'd still like to have all of the Controller
- and Button
-related code in the separate controller.* files.
It seems like this is somewhat related to (but not quite the same as) the following questions:
When you have multiple global constructors, the order in which they are executed is undefined. If the controller
object is instantiated before the map
object is, the controller won't be able to access that map, which results in the segfault. If, however, the map
object is instantiated first, then the controller can access it just fine.
In this case, it seems to be the order in which they appear on the command line. That's why putting your main.cpp
first caused the segfault - the controller
object was getting instantiated first.
I'd recommend moving the instantiation inside your main
, because then you can control exactly how objects are instantiated and in what order.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With