In order to solve this problem Bad memory management? Class member (boolean) value greater than 1, in recursion function, I ran the whole program under Valgrind and found a few memory leak problems that occurred before the step. There were 2 'definitely lost' problems identified in the function CMFLoader.
(here MyDataset is a vector of Molecule objects, and each Molecule object contains an Elements object)
In CMFLoader::loadFile(vector& MyDataset), I originally have
MyDataset.push_back( readMolecule( in_file, word );
where CMFLoader::readMolecule returns a Molecule object. Within the readMolecule function, a new Molecule object is created (but not deleted until the very end of main, more on that later)
Molecule* CMFLoader::readMolecule( ifstream& in_file, string id)
{
Molecule* my_mol = new Molecule( id );
// statements, somewhere along the readFormula function is called
my_mol->setFormula( readFormula( ss ) );
return my_mol;
}
where CMFLoader::readFormula returns an Element object and there is a Molecule::setFormula function to save it to the Molecule object. In readFormula
Elements* CMFLoader::readFormula( stringstream& ss )
{
Elements* my_formula = new Elements();
...
return my_formula;
}
I ran into problems described in the question here, later in the main program. The specific problem occurred at the HammettCheck::checkHammett step. I then changed the above CMFLoader functions to something like this. The problems I encountered earlier seems to have disappeared (but there were other problems later in the program that were no doubt related to the memory leak):
in CMFLoader::loadFile
Molecule* new_mol = new Molecule(word);
MyDataset.push_back( readMolecule( in_file, word ,new_mol) );
where readMolecule now takes in a new argument Molecule* and the new operator is removed within the function. Similarly, in readFormula, I now have
Elements* new_formula = new Elements();
my_mol->setFormula( readFormula( ss, new_formula ) );
etc.
Now of course the memory leak problem is not removed! However, I cannot put in the delete operator within any of the CMFLoader functions as the objects are used later in the main program. Specifically, Elements* is used till the ConjugationCheck::checkConjugation step, and Molecule* is used till the program ends.
Main program goes like this
int main(int argc, char* argv[]){
//initialising an empty array to store our molecules.
vector<Molecule*> MyDataset;
//Read command line inputs.
InputReader* MyInputs = new InputReader();
if( !MyInputs->readInputs(argc, argv) ) {delete MyInputs;return -1;}
//Load CMF file.
CMFLoader* MyLoader = new CMFLoader( MyInputs );
unsigned int min_same_grp = MyLoader->getmin(); //define minimum no of same hammett groups for structure
if( !MyLoader->loadFile( MyDataset ) ) {delete MyLoader;delete MyInputs;return -1;}
delete MyLoader;
cout << MyDataset.size() << " molecules loaded" << endl;
//Remove molecules which are too large.
BigFilter* MyBigFilter = new BigFilter( MyInputs );
if( !MyBigFilter->filterBigLigands( MyDataset ) ) {delete MyBigFilter;delete MyInputs;return -1;}
delete MyBigFilter;
cout << "Molecules left after big ligand filter: " << MyDataset.size() << endl;
//Mark any Hammetts groups found in molecules.
HammettCheck* MyHammettCheck = new HammettCheck(min_same_grp);
if( !MyHammettCheck->loadHammetts() ) {delete MyHammettCheck;delete MyInputs;return -1;}
if( !MyHammettCheck->checkHammett( MyDataset ) ) {delete MyHammettCheck;delete MyInputs;return -1;}
delete MyHammettCheck;
cout << "Molecules containing Hammett Groups: " << MyDataset.size() << endl;
ConjugationCheck* MyConjugationCheck = new ConjugationCheck(min_same_grp);
if( !MyConjugationCheck->checkConjugation( MyDataset ) ) {delete MyConjugationCheck;delete MyInputs;return -1;}
delete MyConjugationCheck;
cout << "Molecules containing conjugated Hammett Groups: " << MyDataset.size() << endl;
DataAdder* MyDataAdder = new DataAdder( MyInputs );
if( !MyDataAdder->addData( MyDataset ) ) {delete MyDataAdder; delete MyInputs;return -1;}
delete MyDataAdder;
//Sorts molecules based on their NLO rating given by NLOCompare.
if (min_same_grp ==1) {sort(MyDataset.begin(), MyDataset.end(), NLOCompare);}
else {sort(MyDataset.begin(), MyDataset.end(), OctuNLOCompare);}
//Saves a new CIF file containing just the predicted NLO molecules.
FileSaver* MyFileSaver = new FileSaver( MyInputs );
if( !MyFileSaver->saveFile( MyDataset ) ) {delete MyFileSaver;delete MyInputs;return -1;}
delete MyFileSaver;
/*
Saves a txt file which can be imported into Excel, showing the
paths to each of the selected Hammett groups in a molecule.
*/
ExcelSaver* MyExcelSaver = new ExcelSaver( MyInputs );
if( !MyExcelSaver->saveFile( MyDataset ) ) {delete MyExcelSaver;delete MyInputs;return -1;}
delete MyExcelSaver;
//Cleans the memory before exiting the program.
for(unsigned int i=0; i < MyDataset.size(); i++){
delete MyDataset[i];
}
delete MyInputs;
return 0;
}
At various points in the program, if the Molecule MyDataset[i] does not fit certain conditions, it is removed using
MyDataset.pop_back();
So this would call the Molecule Destructor, which looks like this
Molecule::~Molecule(void)
{
//Deletes all atoms in molecule.
for(unsigned int i=0; i < mol_atoms.size(); i++){
delete mol_atoms[i];
}
//Deletes all bonds in molecule.
for(unsigned int i=0; i < mol_bonds.size(); i++){
delete mol_bonds[i];
}
//Deletes the class of elements contained.
delete mol_formula;
}
I am not sure what went wrong here. How should I fix the memory leak problem?
The "definitely loss" problems in my Valgrind Memcheck Leak summary
==34809== 400 (96 direct, 304 indirect) bytes in 2 blocks are definitely lost in loss record 24 of 33
==34809== at 0x1000A0679: malloc (vg_replace_malloc.c:266)
==34809== by 0x1000F7F04: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==34809== by 0x10000A3B4: CMFLoader::readMolecule(std::basic_ifstream<char, std::char_traits<char> >&, std::string, Molecule*) (in ./OctuDiscovery)
==34809== by 0x10000B9EE: CMFLoader::loadFile(std::vector<Molecule*, std::allocator<Molecule*> >&) (in ./OctuDiscovery)
==34809== by 0x10000282E: main (in ./OctuDiscovery)
==34809== 12,833 (152 direct, 12,681 indirect) bytes in 1 blocks are definitely lost in loss record 33 of 33
==34809== at 0x1000A0679: malloc (vg_replace_malloc.c:266)
==34809== by 0x1000F7F04: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==34809== by 0x10000B93B: CMFLoader::loadFile(std::vector<Molecule*, std::allocator<Molecule*> >&) (in ./OctuDiscovery)
==34809== by 0x10000282E: main (in ./OctuDiscovery)