I’m creating XmlElements and writing them to a .xml file. This all works and the resulting file is how i want it to be. But my vst plugin crashes everytime after executing this function. I think it happens everytime the juce::XmlElements go out of scope and are destroyed. I’m probably doing something wrong with memory mangement here but i have no idea how to fix it. Any suggestions?
Here is the code:
void createDefaultXml()
{
// Create XML Elements
juce::XmlElement dataElement { juce::XmlElement("DATA") };
juce::XmlElement headersElement { juce::XmlElement("HEADERS") };
juce::XmlElement columns[5] {juce::XmlElement("COLUMN"), juce::XmlElement("COLUMN"), juce::XmlElement("COLUMN"), juce::XmlElement("COLUMN"), juce::XmlElement("COLUMN") };
juce::XmlElement rootElement { juce::XmlElement("TABLE_DATA")} ;
// Set columnId attribute
for (int i = 0; i < 5; i++) columns[i].setAttribute("columnId", i+1);
columns[0].setAttribute("name", "Type");
columns[0].setAttribute("width", 45);
columns[1].setAttribute("name", "Magnitude");
columns[1].setAttribute("width", 72);
columns[2].setAttribute("name", "Angle");
columns[2].setAttribute("width", 72);
columns[3].setAttribute("name", "ID");
columns[3].setAttribute("width", 0);
columns[4].setAttribute("name", "ConjugateID");
columns[4].setAttribute("width", 0);
for (int i = 0; i < 5; i++) headersElement.addChildElement(&columns[i]);
rootElement.addChildElement(&headersElement);
// Create the "DATA" element (empty for now)
rootElement.addChildElement(&dataElement);
// Write the XML document to the file
rootElement.writeTo(xmlFile);
}
Please look what’s written about addChildElement() in the docs:
Child elements are deleted automatically when their parent is deleted, so make sure the object that you pass in will not be deleted by anything else, and make sure it's not already the child of another element.
There is also an example how to add new elements:
// create an outer node called "ANIMALS"
XmlElement animalsList ("ANIMALS");
for (int i = 0; i < numAnimals; ++i)
{
// create an inner element..
XmlElement* giraffe = new XmlElement ("GIRAFFE");
giraffe->setAttribute ("name", "nigel");
giraffe->setAttribute ("age", 10);
giraffe->setAttribute ("friendly", true);
// ..and add our new element to the parent node
animalsList.addChildElement (giraffe);
}
// now we can turn the whole thing into textual XML
auto xmlString = animalsList.toString();
You can even improve that to be a bit safer by using unique_ptr, even though the API doesn’t:
// create an outer node called "ANIMALS"
XmlElement animalsList ("ANIMALS");
for (int i = 0; i < numAnimals; ++i)
{
// create an inner element..
auto giraffe = std::make_unique<XmlElement>("GIRAFFE");
giraffe->setAttribute ("name", "nigel");
giraffe->setAttribute ("age", 10);
giraffe->setAttribute ("friendly", true);
// ..and add our new element to the parent node
animalsList.addChildElement (giraffe.release());
}
// create an outer node called "ANIMALS"
XmlElement animalsList ("ANIMALS");
for (int i = 0; i < numAnimals; ++i)
{
// create an inner element and add it to the parent node in one step
XmlElement* giraffe = animalsList.createNewChildElement ("GIRAFFE");
giraffe->setAttribute ("name", "nigel");
giraffe->setAttribute ("age", 10);
giraffe->setAttribute ("friendly", true);
}
giraffe ends up being a raw, non-owning pointer because the “GIRAFFE” node is already owned and taken care of by the root “ANIMALS” node
// create an outer node called "ANIMALS"
XmlElement animalsList ("ANIMALS");
for (int i = 0; i < numAnimals; ++i)
{
juce::ValueTree giraffe ("GIRAFFE", {
{"name", "nigel"},
{"age", 10},
{"friendly", true}
});
// createXml() returns an unique_ptr, so we need to release it
animalsList.addChildElement (giraffe.createXml().release());
}
Thanks to the initialiser lists the code is way less verbose.
I would consider moving the whole thing to ValueTree anyway, much nicer in terms of memory management. But you can mix and match