views:

89

answers:

2

Okay, I have a function which reads a xml file and creates controls using new and stores them in public member variables of a class called Window:

std::map<const char*, Button*> Buttons;
std::map<const char*, TextBox*> TextBoxes;
std::map<const char*, CheckBox*> CheckBoxes;

The Button, TextBox and CheckBox classes are homemade wrappers of CreateWindowEx.

Here is the function that populates the maps:

void Window::LoadFromXml(const char* fileName)
{
    XMLNode root = XMLNode::openFileHelper(fileName, "Window");

    for(int i = 0; i < root.nChildNode("Button"); i++)
    {           
        Buttons.insert(std::pair<const char*, Button*>(root.getChildNode("Button", i).getAttribute("Name"), new Button));
        Buttons[root.getChildNode("Button", i).getAttribute("Name")]->Init(_handle);
    }   

    for(int i = 0; i < root.nChildNode("CheckBox"); i++)
    {       
        CheckBoxes.insert(std::pair<const char*, CheckBox*>(root.getChildNode("Button", i).getAttribute("CheckBox"), new CheckBox));
        CheckBoxes[root.getChildNode("CheckBox", i).getAttribute("Name")]->Init(_handle);
    }

    for(int i = 0; i < root.nChildNode("TextBox"); i++)
    {               
        TextBoxes.insert(std::pair<const char*, TextBox*>(root.getChildNode("TextBox", i).getAttribute("Name"), new TextBox));
        TextBoxes[root.getChildNode("TextBox", i).getAttribute("Name")]->Init(_handle);
    }
}

Here is the xml file:

<Window>
    <TextBox Name="Email" />
    <TextBox Name="Password" />

    <CheckBox Name="SaveEmail" />
    <CheckBox Name="SavePassword" />

    <Button Name="Login" />
</Window>

The problem is, if I try to access, for example, TextBoxes["Email"]->Width(10);, the program compiles fine, but then crashes when I start it.

I'm calling it from a derived class:

class LoginWindow : public Window
{
public:

    bool OnInit(void) // This function is called by Window after CreateWindowEx and a hwnd == NULL check
    {
        this->LoadFromXml("xml\\LoginWindow.xml"); // the file path is right
        this->TextBoxes["Email"]->Width(10); // Crash, if I remove this it works and all the controls are there
    }
}
+3  A: 

what do things like root.getChildNode("Button", i).getAttribute("CheckBox") return? clearly it's a char* (maybe const), but where is it allocated? Heap? If so, when do you free it?

It is possible depending on the API that it returns a static buffer or something else that doesn't last as long as your map which could lead to crashes and other funky behavior. You should make your maps look like this and not have to worry about it:

std::map<std::string, Button*> Buttons;
std::map<std::string, TextBox*> TextBoxes;
std::map<std::string, CheckBox*> CheckBoxes;
Evan Teran
+5  A: 

The problem likely is, that your map has const char* as keys - and that doesn't mean strings, but pointers. Which means it sees two different pointers to the same strings (eg. your string literal "Email" and characters "Email" you've read from the file) as different, hence it doesn't find the pointer to the textbox on the "crash" line (and executes a method of a nonexistent object instead). I suggest you change your map types to std::map<std::string, ...>.

Other than that, I'd suggest you to use std::make_pair(a, b) instead of manually specifying the type of the pair structure.

jpalecek
thanks, jpalecek, btw, was this a beginner, intermidiate or advanced question?
Martin