I Have this function, its purpose is to delete a pointer of class BaseFile from a vector called children
//children is vector of type vector<BaseFile*>
void Directory::removeFile(BaseFile* file)
{
for(int i = 0 ; (unsigned)i < children.size() ; i++)
{
if ((children[i]->getName()).compare(file->getName()) == 0)
{
BaseFile* a = children[i];
children.erase(children.begin()+i);
if(a != nullptr)
{
delete a;//err in this line : double free or corruption
}
}
}
}
first question is why I AM getting an error in the line (delete a;) ? dose the method erase removes the pointer an delete it? if yes how can i remove the pointer from the vector without deleting it's content in Heap/Stack?
What you need to do is to use std::remove_if
to obtain the vector without the matching element.
However, once you have performed the call to std::remove_if
you have no way to delete
the matching items as the documentation states (emphasis mine):
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. Relative order of the elements that remain is preserved and the physical size of the container is unchanged. Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition).
Therefore we'll handle the deletion directly in the predicate. Note that we must also take care not to double free anything so we'll keep track of the deleted item through the use of an std::unordered_set
void Directory::removeFile(BaseFile *file) {
std::unordered_set<BaseFile*> deleted_set { file }; // Just to avoid deleting the input argument if it's stored in children as well...
auto match_it = std::remove_if(begin(children), end(children),
[&](BaseFile *current_file) -> bool {
bool result = current_file->getName().compare(file->getName()) == 0;
if (result && end(deleted_set) == deleted_set.find(current_file)) {
delete current_file;
deleted_set.insert(current_file);
}
return result;
});
children.erase(match_it, end(children));
}
Finally, I hope that the pointer you give as the file
argument isn't a member of children
as well and if it is, that you don't end up delete
-ing it!
Note: Wouldn't it be possible to use smart pointers in your case? It seems that the Directory
object has ownership on the BaseFile
objects stored in children
... So maybe std::unique_ptr
would help...