void FileBot::clearMemory() { for(FileNode &T : fileList) { T.sibling.erase_and_dispose(T.sibling.begin(), T.sibling.end(), DisposeFileNode()); } fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode()); }In the new implementation, one I can think of is a recursive function. The recursive function usage is like this: As long as there are file objects inside the sibling, dive into the sibling and look for any other file objects inside the sibling. If it doesn't contain any file object, it will return. This return will go back up one level, then only clean the sibling for the particular file object. The process will continue until it reaches to the beginning level of the path, then only remove the remaining memory from container.
void FileBot::clearMemory(FileNode *fileNode) { bool beginning = false; if( fileNode == NULL ) { fileNode = &*(fileList.begin()); beginning = true; } if( fileNode->sibling.size() > 0 ) { cout << "scanning current node: " << fileNode << endl; clearMemory(&*(fileNode->sibling.begin())); } else return; cout << "clean sibling memory: " << fileNode << " sibling size: " << fileNode->sibling.size() << endl; fileNode->sibling.erase_and_dispose(fileNode->sibling.begin(), fileNode->sibling.end(), DisposeFileNode()); if( beginning == true) { cout << "clean root. Root size [" << fileList.size() << "]" << endl; fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode()); } }Notice the clearMemory(FileNode* ) is expecting an argument. I have declared this argument to NULL when it is first called. Something like this:
class FileBot { public: void clearMemory(FileNode *fileNode = NULL); ... ... };Thanks to the C++ great feature. When it is NULL, this indicate the beginning of the file path, after the subsequent call to the clearMemory(), it is no longer NULL anymore. And when the sibling size is zero, clearMemory() wouldn't get called. Thus, no worry about that.
In addition to that, there is a memory leak happened on following test case:
/* load 1 level parent path * */ BOOST_AUTO_TEST_CASE(TL_4) { BOOST_TEST_MESSAGE("TC4 : load 1 level parent path"); #if defined(WIN32) BOOST_TEST_MESSAGE("Test path: D:"); FileBot fb("D:"); #else BOOST_TEST_MESSAGE("Test path: /home"); FileBot fb("/home"); #endif string path = ""; if( fb.initialize() == 1 ) path = fb.verifyFileList(); #if defined(WIN32) BOOST_TEST(path == "D:"); fb.clearMemory(); #else BOOST_TEST(path == "/home"); #endif }This is due to something was not being handle probably in clearMemory(), end up the fileList wasn't clear. This test case consists of a file path with only one level, such as C:\ in Windows or /home in Linux. For Linux, it is a little bit special, /home is actually 2 levels file path. One is root path, and home is under the root. For my requirement, I just treat it as 1 level. Unlike Windows, the root is represented by a label, C:\.
I can't think of a perfect solution to resolve this defect yet. For now, I make a validation check at the beginning of the function:
void FileBot::clearMemory(FileNode *fileNode) { bool beginning = false; // this parent have no child if( (&*(fileList.begin()))->sibling.size() == 0 ) { fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode()); return; } ... ... }When I see there is no sibling, clean up the mess and then bail out from the function.