New to JUCE & C++. Advice on code style?


#1

Hello,

I’m working my way through JUCE by trying to convert an existing project I am studying from C++ to JUCE. The existing code is a good starting point for what I want to do, but I am hoping to convert the basic C++ stuff to JUCE to make the code more uniform when I start adding the new stuff. I have programed in Java for a while now, but C++ seems very, very different :slight_smile: I think I’m getting the idea for the most part, but I’m unsure if I’m making mistakes, abusing/misusing the pointer/reference thing, or writing “ugly” code in general. Hopefully someone can shed some light.

Currently I am trying to parse an XML file by Element. Each element contains several attributes. I want to pack these into a “Observations” class. Sort of like a node container. Here is my attempt to parse the xml. The main function I’m most concerned about is bool LoadDataSet(const String& fileName);

Thanks for any help or thoughts

Owen

J_DataSet.h

/*
  ==============================================================================

    J_DataSet.h
    Created: 6 Nov 2010 11:58:44am
    Author:  owen vallis

  ==============================================================================
*/

#ifndef __J_DATASET_H_45A3F85D__
#define __J_DATASET_H_45A3F85D__

#include "../JuceLibraryCode/JuceHeader.h"

#include "Observation.h"

class J_DataSet  
	{
	public:
		float GetDescriptorValue(long observationIndex, long descriptorIndex) const;
		long GetNumberOfDescriptors() const;
		long GetNumberOfObservations() const;
		bool LoadDataSet(const String& fileName);
		J_DataSet();
		virtual ~J_DataSet();
		
	private:
		long numberOfDescriptors;
		long numberOfObservations;
		OwnedArray<Observation> data;
};



#endif  // __J_DATASET_H_45A3F85D__

J_DataSet.cpp

/*
 ==============================================================================
 
 J_DataSet.cpp
 Created: 6 Nov 2010 11:58:44am
 Author:  owen vallis
 
 ==============================================================================
 */

#include "J_DataSet.h"


J_DataSet::J_DataSet()
{
	numberOfDescriptors=0;
	numberOfObservations=0;
}

J_DataSet::~J_DataSet()
{
	//reclaim the observation OwnedArray
	data.clear(true);
}

bool J_DataSet::LoadDataSet(const String& fileName)
{
	/*	Owen Vallis (based off code by Robert Kirk DeLisle November 27 2001)
	 November 6 2010
	 Purpose:	Load data into the dataset from the specified file.  
	 This function assumes CLEAN!! data files in XML format.
	 Any number of descriptors and observations are allowed, 
	 but the first column is treated as the endpoint
	 
	 Parameters:	fileName:	Reference to a string containing the
	 complete path of the data file.
	 numOfObservations:	Reference variable which is changed by this
	 function to contain the number of observations
	 numOfDescriptors:	Reference variable which is changed by this
	 function to contain the number of descriptors
	 
	 Return:		TRUE if successful, FALSE if unsuccessful
	 */
	
	File datafile(fileName); //open the data file
	
	if(datafile.hasFileExtension(T(".xml")) )
	{
		XmlDocument xmlDataSet (datafile);
		XmlElement* mainXmlElement = xmlDataSet.getDocumentElement();
		if (mainXmlElement == 0)
		{
			String error = xmlDataSet.getLastParseError();
			
			return false;
		}
		else
		{
			XmlElement* currentXmlElement = mainXmlElement->getFirstChildElement();
			
			//count the number of Descriptors
			numberOfDescriptors = currentXmlElement->getNumAttributes();
			
			//now save the actual values of the endpoints and the descriptors
			Observation * currentObservation = 0;
			
			numberOfObservations = mainXmlElement->getNumChildElements();
			
			for(int i = 0; i < numberOfObservations; i++)
			{
				//make a new observation to hold the data
				currentObservation = new Observation;
				currentObservation->SetIndex(i);
				
				//unpack and save the Descriptor values into the current Observation
				for(int j = 0; j < numberOfDescriptors; j++)
				{
					currentObservation->AddDescriptor(currentXmlElement->getDoubleAttribute(String(j)) );
				}
				
				//add current Observation to data collection
				data.add(currentObservation);
				
				//grab next XmlElement
				if(currentXmlElement != 0)
				{
					currentXmlElement = currentXmlElement->getNextElement();
				}
				else
				{
					return false;
				}
			}
			
			//clean up pointers
			delete mainXmlElement;
			mainXmlElement = 0;
			delete currentXmlElement;
			currentXmlElement = 0;
		}
	}
	
	return true;
}

long J_DataSet::GetNumberOfDescriptors() const
{
	/*	Robert Kirk DeLisle
	 November 27 2001
	 Purpose:	Retrieve the total number of descriptors
	 
	 Parameters:	none
	 
	 Return:		The number of descriptors (columns) in the dataset.
	 */
	
	return numberOfDescriptors;
	
}

long J_DataSet::GetNumberOfObservations() const
{
	/*	Robert Kirk DeLisle
	 November 27 2001
	 Purpose:	Retrieve the total number of Observations
	 
	 Parameters:	none
	 
	 Return:		The number of Observations (rows) in the dataset.
	 */
	
	return numberOfObservations;
}

float J_DataSet::GetDescriptorValue(long observationIndex, long descriptorIndex) const
{
	/*	Owen Vallis (based off code by Robert Kirk DeLisle November 27 2001)
	 November 6 2010
	 Purpose:	Return the value of the descriptor specified for the observation specified
	 
	 Parameters:	observationIndex:	The zero-based index of the observation of interest
	 
	 descriptorIndex:	The zero-based index of the descriptor of interest
	 
	 Return:		the value of the specified descriptor-observation pair
	 */
	
	return data[observationIndex]->GetDescriptorValue(descriptorIndex);
	
}

#2

It’s not that hard to convert from C++ to JUCE, as JUCE is already C++ :smiley:

General guidelines are…
1- check always if your files exists (File::existsAsFile) before opening them
2- use a ScopedPointer to manage your new’ed object, this take cares of deallocating memory for you in a safe way
3- usually is better to have the function documentation in the header rather than in the implementation…


#3

Thanks for the tips!