Hey
I’ve come across a strange problem and a couple of confusing memory leaks when using XmlElement objects. I’m sure it’s a just simple problem that I don’t understand simply from my lack on knowledge on using the XmlElement class.
In a nut shell, I am trying to implement a system that allows settings within an app to be saved into a number of ‘presets’ which can then be saved as a group to disk. The saved file can then be loaded back into the app and split back into these separate presets. I’m sure you’re familiar with this idea. In my program I’ve created an OwnedArray of XmlElement objects (which are the ‘presets’) which get given child elements which hold data/settings. When the presets need saving to disk each of these objects in the OwnedArray are added as child elements to another XmlElement which is then saved to disk as an XmlDocument. Below is a simple example of my program:
.h file:
[code]//
// DataStorage.h
// sdaJuce
//
// Created by Liam Meredith-Lacey on 25/11/2011.
// Copyright 2011 UWE. All rights reserved.
//
#ifndef H_DATASTORAGE
#define H_DATASTORAGE
#include <juce.h>
class DataStorage
{
public:
DataStorage();
~DataStorage();
void save();
void load();
void savePreset (int presetNumber);
private:
OwnedArray presetData;
};
#endif //H_DATASTORAGE[/code]
.cpp file
[code]//
// DataStorage.cpp
// sdaJuce
//
// Created by Liam Meredith-Lacey on 25/11/2011.
// Copyright 2011 UWE. All rights reserved.
//
#include “DataStorage.h”
DataStorage::DataStorage()
{
//init OwnedArray
for (int i = 0; i < 3; i++)
{
presetData.add(new XmlElement(“PRESET_” + String(i)));
}
}
DataStorage::~DataStorage()
{
}
void DataStorage::save()
{
//open FileChooser
FileChooser saveFileChooser(“Create a file to save…”, File::getSpecialLocation (File::userDesktopDirectory), “*.tst”);
if (saveFileChooser.browseForFileToSave(false))
{
//create a file based on users selection
File savedFile(saveFileChooser.getResult());
String stringFile = savedFile.getFullPathName();
stringFile = stringFile + ".tst";
savedFile = stringFile;
bool overwrite = true;
//check to see if the file already exists
if (savedFile.existsAsFile())
overwrite = AlertWindow::showOkCancelBox(AlertWindow::WarningIcon, "This File Already Exists!", "Are you sure you want to overwrite this file?");
if (overwrite == true)
{
savedFile.deleteFile();
savedFile.create();
//create new XmlElement
XmlElement *savedData = new XmlElement ("SAVED_DATA");
//add presetData XmlElements as Child XmlElements
for (int i = 0; i < 3; i++)
{
std::cout << "Child element being added to SAVED_DATA\n";
savedData->addChildElement(presetData[i]);
}
std::cout << "All Child elements have been added to SAVED_DATA\n";
//create document
String xmlDoc = savedData->createDocument(String::empty, false);
//add to saved File
savedFile.appendText(xmlDoc);
}
}
}
void DataStorage::load()
{
//open FileChooser
FileChooser loadFileChooser(“Select a .tst file to load…”, File::getSpecialLocation(File::userDesktopDirectory), “*.tst”);
if (loadFileChooser.browseForFileToOpen())
{
//get file selected by the user
File loadedFile (loadFileChooser.getResult());
//parse selected XmlDocument to an XmlElement
XmlElement *loadedXml = XmlDocument::parse(loadedFile);
if (loadedXml != nullptr && loadedXml->hasTagName("SAVED_DATA"))
{
//load the child elements of loadedXml and put them in the presetData objects
for (int i = 0; i < 3; i++)
{
//clear the xmlelement for the current preset number
presetData[i]->deleteAllChildElements();
std::cout << "Child element being loaded from SAVED_DATA\n";
//put the loaded xml data into the xmlelement for the current preset
presetData.insert (i, loadedXml->getChildByName("PRESET_" + String(i)));
}
}
}
}
//adds child XmlElement’s to the presetData XmlElements
void DataStorage::savePreset (int presetNumber)
{
//clear presetData object
presetData[presetNumber]->deleteAllChildElements();
//create child XmlElement
XmlElement *testData1 = new XmlElement ("TEST_DATA_1");
//give it some data
testData1->setAttribute("A", 1);
testData1->setAttribute("B", 2);
testData1->setAttribute("C", 3);
//add as a child to presetData
presetData[presetNumber]->addChildElement(testData1);
//create child XmlElement
XmlElement *testData2 = new XmlElement ("TEST_DATA_2");
//give it some data
testData2->setAttribute("A", 4.0);
testData2->setAttribute("B", 5.0);
testData2->setAttribute("C", 6.0);
//add as a child to presetData
presetData[presetNumber]->addChildElement(testData2);
//create child XmlElement
XmlElement *testData3 = new XmlElement ("TEST_DATA_3");
//give it some data
testData3->setAttribute("A", "Seven");
testData3->setAttribute("B", "Eight");
testData3->setAttribute("C", "Nine");
//add as a child to presetData
presetData[presetNumber]->addChildElement(testData3);
}
[/code]
Here are the two problems I’m getting:
- After running either the load() or save() functions I get a ‘Leaked object detected: 1 instance of class XmlElement’ error.
- When trying to run either the load() or save() functions for a second time the program get’s stuck indefinitely in the function, usually within the functions for loops.
Any answers to why I’m running into these to problems would be greatly appreciated; I’ve been trying to fix this for many many hours!
Thanks.