简体   繁体   English

在创建对象的功能之外的其他对象中删除对象的位置/方式

[英]Where/how to delete an object within another object, outside the function that it was created in

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. 在递归函数中类成员(布尔值)的值大于1,我在Valgrind下运行了整个程序,发现在此步骤之前发生了一些内存泄漏问题。 There were 2 'definitely lost' problems identified in the function CMFLoader. 在函数CMFLoader中确定了2个“绝对丢失”的问题。

(here MyDataset is a vector of Molecule objects, and each Molecule object contains an Elements object) (此处MyDataset是分子对象的向量,每个分子对象都包含一个Elements对象)

In CMFLoader::loadFile(vector& MyDataset), I originally have 在CMFLoader :: loadFile(vector&MyDataset)中,我最初有

MyDataset.push_back( readMolecule( in_file, word );

where CMFLoader::readMolecule returns a Molecule object. 其中CMFLoader :: readMolecule返回一个Molecule对象。 Within the readMolecule function, a new Molecule object is created (but not deleted until the very end of main, more on that later) 在readMolecule函数中,创建了一个新的Molecule对象(但直到main的最后才删除,稍后再介绍)

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. 其中CMFLoader :: readFormula返回一个Element对象,并且有一个Molecule :: setFormula函数将其保存到Molecule对象。 In readFormula 在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. 在HammettCheck :: checkHammett步骤中发生了特定的问题。 I then changed the above CMFLoader functions to something like this. 然后,我将上面的CMFLoader函数更改为类似的内容。 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 在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. 现在readMolecule接受一个新的参数Molecule *,并且在该函数中删除了新的运算符。 Similarly, in readFormula, I now have 同样,在readFormula中,我现在有

 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. 但是,我无法在任何CMFLoader函数中放入delete运算符,因为稍后将在主程序中使用这些对象。 Specifically, Elements* is used till the ConjugationCheck::checkConjugation step, and Molecule* is used till the program ends. 具体来说,将使用Elements *直到ConjugationCheck :: checkConjugation步骤为止,并使用Molecule *直到程序结束为止。

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 在程序的各个点上,如果Molecule MyDataset [i]不满足某些条件,则使用以下命令将其删除

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 我的Valgrind Memcheck泄漏摘要中的“绝对损失”问题

==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)

More a comment than an answer, but too long for a comment: 评论多于答案,但评论太长:
In next function, it doesn't make sense to use dynamic memory: 在下一个函数中,使用动态内存没有意义:

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;
}

You could replace it with: 您可以将其替换为:

Molecule CMFLoader::readMolecule( ifstream& in_file, string id)
{
Molecule my_mol( id );
// statements, somewhere along the readFormula function is called
my_mol.setFormula( readFormula( ss ) );
return my_mol;
}

This solves already 1 possible memory leak, but there might be reasons why the dynamic memory version is needed/preferred, in which case the already mentioned unique_ptr should be used. 这样已经解决了1种可能的内存泄漏,但是可能由于某些原因需要/首选动态内存版本,在这种情况下,应使用已经提到的unique_ptr。

If you want to do something like this, I would suggest that you take a look at std::auto_ptr class, or at least the concepts of smart pointers, or auto pointers. 如果您想做这样的事情,我建议您看一下std :: auto_ptr类,或者至少看一下智能指针或自动指针的概念。 You should rely on RAII (Resource Aquisition Is Initialization) paradigm, meaning that the memory management should be done by objects themselves: avoid basic pointers and self written memory management code whenever you can. 您应该依赖RAII(资源获取即初始化)范式,这意味着内存管理应由对象自己完成:尽可能避免使用基本指针和自写的内存管理代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM