deery50
deery50

Reputation: 65

C++ rapidxml access violation after a certain amount of time (visual studio 2013)

I have been using the excellent rapidxml library to read and use information from XML files to hold cutscene information for a game I am programming in C++. I have run into an odd problem,

I start by loading the XML file into a rapidxml::xmldocument<>* from std::ifstream* XMLFile

std::stringstream buffer; //Create a string buffer to hold the loaded information
buffer << XMLFile->rdbuf(); //Pass the ifstream buffer to the string buffer
XMLFile->close(); //close the ifstream
std::string content(buffer.str()); //get the buffer as a string
buffer.clear();
cutScene = new rapidxml::xml_document<>;
cutScene->parse<0>(&content[0]);
root = cutScene->first_node();

my cutscene xml file is made up of "parts" and at the beginning I want to load all of those parts (which are all xml_nodes) into a vector

//Load parts
if (parts->size() == 0) {
    rapidxml::xml_node<>* partNode = root->first_node("part");
    parts->push_back(partNode);
    for (int i = 1; i < numParts; i++) {
        parts->push_back(partNode->next_sibling());
        printf("name of part added at %i: %s.\n", i, parts->at(i)->name());
    }
}

That last line prints "name of part added at 1: part" to the console. The problem is for some reason, whenever I try to access the vector and print the same name of that same specific part not as a part of this method, the name can be accessed but is just a random string of letters and numbers. It seems that for some reason rapidxml is deleting everything after my load method is complete. I am still new to posting on stackoverflow so if you need more information just ask, thanks!

Upvotes: 1

Views: 490

Answers (1)

alexm
alexm

Reputation: 6882

Rapidxml is in-situ xml parser. It alters the original string buffer (contentin your case) to format null-terminated tokens such as element and attribute names. Secondly, the lifespan of tree nodes referenced byparts items is defined by xml_document (currscene) instance.

Keep currscene and content instances together with the vector, this will keep the vector items alive as well. e.g:

 struct SceneData
 {
    std::vector<char> content;
    rapidxml::xml_document<> cutScene;
    std::vector<rapidxml::xml_node<>*> parts;

    bool Parse(const std::string& text);
 };

 bool SendData::Parse(const std::string& text)
 {
       content.reserve(text.length() + 1);
       content.assign(text.begin(), text.end());
       content.push_back('\0');

       parts.clear();

       try
       {
         cutScene.parse<0>(content.data());
       }
       catch(rapidxml::parse_error & err)
       {
           return false;
       }


       // Load parts.   
       rapidxml::xml_node<>* root = cutScene.first_node();      
       rapidxml::xml_node<>* partNode = root->first_node("part");
       parts->push_back(partNode);
       for (int i = 1; i < numParts; i++) {
             parts->push_back(partNode->next_sibling());
             //printf("name of part added at %i: %s.\n", i, parts->at(i)->name());
       }

       return true ;
  }

EDITED

The parser expects a sequence of characters terminated by '\0 as input. Since a buffer referenced by &string[0] is not guaranteed to be null-terminated, it is recommended to copy the string content into std::vector<char>.

Upvotes: 0

Related Questions