Tuesday, April 17, 2018

Boost Intrusive Set lookup function doesn't accept search key as object?

Would it be easier if I change the intrusive list to intrusive set? Okay, my initial goal is to capture the files into the memory, which is an intrusive list for my case, and then search through the list for each input entry. The input entry might go up 1000 items in total. Now the problem here is I had never decide what algorithm to use for the searching part. Then I come across the intrusive set does provide the API for me to work with, code sample below is my experiment on this:
class FileNode3;
typedef boost::intrusive::set<FileNode3, compare<std::greater<FileNode3> >, constant_time_size<false> > BaseSet;


class FileNode3 : public set_base_hook<link_mode<safe_link> > {
public:
    boost::filesystem::path root;
    boost::filesystem::path name;
    char type; // f is file, d is directory

    BaseSet sibling;

    FileNode3() {}
    FileNode3(boost::filesystem::path name_) : name(name_) {}
    FileNode3(boost::filesystem::path name_, const char type_) : name(name_), type(type_) {}

public:
    void setName(boost::filesystem::path name) { this->name = name; }
    void setRoot(boost::filesystem::path root) { this->root = root; }
    void setType(char type) { this->type= type; }

    friend bool operator< (const FileNode3 &a, const FileNode3 &b)
        {  return a.name.compare(b.name) < 0;  }

    friend bool operator> (const FileNode3 &a, const FileNode3 &b)
        {  return a.name.compare(b.name) > 0;  }

    friend bool operator== (const FileNode3 &a, const FileNode3 &b)
        {  return a.name.compare(b.name) == 0;  }
};

BOOST_AUTO_TEST_CASE(TL_IntrusiveSet, *boost::unit_test::precondition(skipTest(false)))
{
    struct FileNodeEqual
    {
        bool operator()(const char *search, const FileNode3 &node) const
        {
            cout << "StrEqual arg1: " << search << " " << node.name.c_str() << endl;

            return strcmp(search, node.name.c_str()) == 0 ? false : true;
        }

        bool operator()(const FileNode3 &node, const char *search) const
        {
            cout << "StrEqual arg2: " << search << " " << node.name.c_str() << endl;

            return strcmp(node.name.c_str(), search) == 0 ? false : true;
        }
    };

    BaseSet s1;

    FileNode3 fn3;
    fn3.name = "fileB";
    fn3.type = 'f';

    FileNode3 fn1;
    fn1.name = "path_A";
    fn1.type = 'd';
    fn1.sibling.push_back(fn3);

    FileNode3 fn2;
    fn2.type = 'f';
    fn2.name = "fileA";

    s1.insert(fn1);
    s1.insert(fn2);

    FileNode3 f;
    f.name = "fileB";
    f.type = 'd';

    boost::intrusive::set<FileNode3>::iterator it = s1.find(f.name.c_str(), FileNodeEqual());

    FileNode3 *n = (&*it);

    if( it == s1.end() ) {
        cout << "record not found" << endl;
    }
    else {
        FileNode3 *n = (&*it);
        cout << "record found: " << n->name << endl;
    }

    if( fn1.sibling.size() > 0 ) {
        cout << "fn1 sibling has more child: " << fn1.sibling.size() << endl;

        boost::intrusive::set<FileNode3>::iterator it = fn1.sibling.find(fn3);

        if( it == s1.end() ) {
            cout << "record not found" << endl;
        }
        else {
            FileNode3 *n = (&*it);
            cout << "record found: " << n->name << endl;
        }
    }

    s1.remove_node(fn1);
    s1.remove_node(fn2);
    s1.remove_node(fn3);

    cout << "Test 1 end!" << endl;
}
But that is one problem with this code, I can only compare the name property of this object. How can I compare the rest of the properties of the object? Why don't I just pass down the whole object and then do the comparison? Then I modify the FileNodeEqual struct as follows, the search key has become an FileNode3 instead of char*:
struct FileNodeEqual
    {
        bool operator()(const FileNode3 &search, const FileNode3 &node) const
        {
            cout << "StrEqual arg1: " << search.name.c_str() << " " << node.name.c_str() << endl;

            return true;
        }

        bool operator()(const FileNode3 &node, const FileNode3 &search) const
        {
            cout << "StrEqual arg2: " << search.name.c_str() << " " << node.name.c_str() << endl;

            return true;
        }
    };
Then the compiler will complain following error to me:
error: 'bool testlab::TL_IntrusiveSet::test_method()::FileNodeEqual2::operator()(const testlab::FileNode3&, const testlab::FileNode3&) const' cannot be overloaded
         bool operator()(const FileNode3 &node, const FileNode3 &search) const
              ^~~~~~~~
error: with 'bool testlab::TL_IntrusiveSet::test_method()::FileNodeEqual2::operator()(const testlab::FileNode3&, const testlab::FileNode3&) const'
         bool operator()(const FileNode3 &search, const FileNode3 &node) const
              ^~~~~~~~
I have tested with other primitive data types are working fine. Not sure whether this is due to the performance penalty when calling those functions, thus it was design not allow to take any expensive object?

Wednesday, February 28, 2018

redesigning the constructChildPath();

inpuPath a former member of class FileBot. I decided to removed this member variable in the recent design for constructChildPath(). There are 5 test cases for this design specification - capturing files, 2 of the test case were failed, which is test case 4 and 5.
  1. one file is captured without sub folder.
  2. two files are captured without sub folder.
  3. one files are captured when there is a sub folder.
  4. one files are captured in directory under test and one file in sub folder.
  5. zero file are captured in directory under test and one file in sub folder.
The root cause for this failure was due to the misused of inputPath as reference point in constructChildPath().
void FileBot::constructChildPath()
{
    vector<path> pathList;
 
    // where am I now?
    BOOST_LOG_TRIVIAL(info) << "current path: " << inputPath << inputPath.filename() << endl;
 
    // capture the paths/files list under the source
    copy(filesystem::directory_iterator(inputPath), filesystem::directory_iterator(), back_inserter(pathList));

    ...
    ...
}
For this purpose, I decide to remove this member variable to make constructChildPath() more robust in processing file directory. To do this, the first make over is to build a method to construct the path to feed directory_iterator().
string FileBot::constructPathAddress(FileNode *node)
{
    if( root == nullptr )
        return "";

    string filePath = "";

    if( node->getParentNode() != nullptr )
        filePath = constructPathAddress(node->getParentNode());

    return filePath + node->getName().string() + string(1, boost::filesystem::path::preferred_separator);
}
Unlike the previous version, the constructChildPath() has now been transformed into a recursive function. Take note on the inputPath is getting the outcome from constructPathAddress() and then feed into directory_iterator().
void FileBot::constructChildPath(FileNode *currentRootNode)
{
    vector<path> pathList;

    // construct path address
    string inputPath = constructPathAddress(currentRootNode);

    // capture the paths/files list under the source
    copy(filesystem::directory_iterator(inputPath), filesystem::directory_iterator(), back_inserter(pathList));

    std::sort(pathList.begin(), pathList.end());

    // scan through path and those files sit in that path
    // scan for files in sub directory if there is any sub directory in that path
    for(vector<path>::const_iterator it(pathList.begin()); it != pathList.end(); ++it) {
        string file = FileHelper::convertPathToString((*it));

        if( is_directory(file) ) {
            FileNode *node = new FileNode();
            node->setName(file.substr(file.find_last_of(boost::filesystem::path::preferred_separator) + 1, file.length()));
            node->setType('d');
            node->setParentNode(currentRootNode);

            currentRootNode->sibling.push_back(*node);

            BOOST_LOG_TRIVIAL(info) << "subFolderName : " << node->getName().string() << " : " << node;

            constructChildPath(node);
        }
        else {
            FileNode *node = new FileNode();
            node->setName(file.substr(file.find_last_of(boost::filesystem::path::preferred_separator) + 1, file.length()));
            node->setType('f');
            node->setParentNode(currentRootNode);

            currentRootNode->sibling.push_back(*node);
        }
    }
}
Last is to reassign the task of constructor to validatePath(). I just felt that this task doesn't suitable to put into the constructor since it only use by constructParentPath().
path FileBot::validatePath(boost::filesystem::path filePath)
{
    // remove trailing file separator if found any
    char lastChar = filePath.generic_string().at(filePath.generic_string().length() - 1);
    if( lastChar == '/' )
        filePath = filePath.generic_string().substr(0, filePath.generic_string().length() - 1);

    return filePath;
}
Then in constructParentPath() just call this method to update the input value again.
FileNode* FileBot::constructParentPath(boost::filesystem::path inputPath)
{
    inputPath = validatePath(inputPath);

    // bail out if the path doesn't exists
    if( !exists(inputPath.generic_string()) )
        return nullptr;

    ...
    ...
}

Sunday, February 25, 2018

Grouping test cases with test suite

Sometimes I just want to skip those unit test cases that have already been pass and focus those test cases on my current development. And then re-run again the whole unit test case again when I have finished the task to ensure no flaw happened to the other unit test cases. Sometimes it is so annoying to run all unit test cases that are not relevant to the task I'm currently working on. I found out one trick that could allow me to control which unit test code should execute and which should stop.

The code snippet below is the ordinary declaration for my unit test code, this declaration form will be executed whenever the code were run.
BOOST_AUTO_TEST_CASE(TL_1)
{
   ...
}
Then later I added some spice to tell the framework whether the unit test case should be executed or not. Following code snippet is the trick I have done for this purpose.
BOOST_AUTO_TEST_CASE(TL_1, *boost::unit_test::enable_if<false>())
{
   ...
}
In my case, this would be a great help. I don't need to wait for all unit test cases are finished in order to see the result. Some more there is only one or two test cases I can really focus on for the same tasks at the same time. Now, as my unit test code are expanding, I need more flexibility and the ability to group relevant test cases together in one source file, and then I can decide which test code to run. Here is the code snippet for the solution.
BOOST_AUTO_TEST_SUITE(testlab, *boost::unit_test::label("testlab"))

BOOST_AUTO_TEST_CASE(TL_1, *boost::unit_test::enable_if<false>())
{
   ...
   ...
}

BOOST_AUTO_TEST_SUITE_END()
With this code, the test case are grouped under the test suite named testlab. When the code is run, all test cases under this suite will be execute. But there is one flaw in this code, the enable_if() is not working. The test will continue to execute even though it is false. Not only that, neither disabled() and enabled() are working. Luckily precondition() comes to a rescue. The code snippet below tells the framework to continue to execute the test case.
struct skipTest
{
    bool skip;
    skipTest(bool s) : skip(s){}

    boost::test_tools::assertion_result operator()(boost::unit_test::test_unit_id)
    {
        if( skip == false )
            return true;
        else
            return false;
    }
};

BOOST_AUTO_TEST_CASE(TL_1, *boost::unit_test::precondition(skipTest(false)))
{
   ...
   ...
}
As of now, the test suite will help me to control which group of test case to execute and precondition() will allow me to choose which test case should skip whenever I want during the development.

Friday, February 16, 2018

Improving the piece in constructParentPath() and constructChildPath()

In the existing FileBot class design, I have an inputPath class member variable.
class FileBot
{
public:
   FileBot(boost::filesystem::path filePath);

   int constructParentPath();
   void constructChildPath();

   ...
   ...

private:
   boost::filesystem::path inputPath;
};
The purpose of this variable is to keep track of the starting point where the files should begin to search with. It is so important that nothing is missed during the initialization, otherwise nothing will get from the search. Thus I'm doing the initialization through the constructor.
FileBot::FileBot(boost::filesystem::path filePath)
{
    // remove trailing file separator if found any
    char lastChar = filePath.generic_string().at(filePath.generic_string().length() - 1);
    if( lastChar == '/' )
        inputPath = filePath.generic_string().substr(0, filePath.generic_string().length() - 1);
    else
        inputPath = filePath;
}
In the client code, the programmer must instantiate the class through the following way. Indirectly the variable will get initialized as well.
FileBot fb("/home");

// or

FileBot *fb = new FileBot("/home");
And then this variable was also incorporated in other methods such as loading path into memory. There are 2 scenarios on loading path into memory; the first scenario is to load the parent path into memory. Say for example when the given input value is /home/user, then only the particular home and user were constructed into memory. Any other files located under the /home directory will be ignored. This is the piece of this construct:
int FileBot::constructParentPath()
{
    // bail out if the path doesn't exists
    if( !exists(inputPath.generic_string()) )
        return 0;

    // construct the parent path first
    string path = inputPath.generic_string();
    FileNode *parent = NULL;

    typedef split_iterator<string::iterator> string_split_iterator;
    for( string_split_iterator it = make_split_iterator(path, first_finder("/", is_equal()));
         it != string_split_iterator();
         ++it)
    {
        FileNode *node = new FileNode();
        node->setType('d');
        node->setName(copy_range<string>(*it));

        cout << "value inserted: [" << copy_range<string>(*it) << "]" << endl;

        if( parent == NULL ) {
            fileList.push_back(*node);
        }
        else
            parent->sibling.push_back(*node);

        parent = node;

        cout << "parent: " << parent;
        cout << " parent value: " << parent->getName();
        cout << " sibling size: " << parent->sibling.size() << endl;
    }

    // keep the current path in memory
    root = parent;

    cout << "***** debug : root node " << root << " : " << root->getName() << endl;

    return 1;
}

The second scenario would be loading the child path into memory. This time it will load all the files under the directory and expand to load the files in any other subdirectories (if any). Continuing from the previous example, /home/user, this section will load the files under the user directory, including the underlying sub directory. The construct for this is as follows:
void FileBot::constructChildPath()
{
    vector<path> pathList;

    // where am I now?
    BOOST_LOG_TRIVIAL(info) << "current path: " << inputPath << inputPath.filename() << endl;

    // capture the paths/files list under the source
    copy(filesystem::directory_iterator(inputPath), filesystem::directory_iterator(), back_inserter(pathList));

    std::sort(pathList.begin(), pathList.end());

    // scan through path and those files sit in that path
    // scan for files in sub directory if there is any sub directory in that path
    for(vector<path>::const_iterator it(pathList.begin()); it != pathList.end(); ++it) {
        string file = FileHelper::convertPathToString((*it));

        // extract the file name from the path
        file = file.substr(file.find_last_of(boost::filesystem::path::preferred_separator) + 1, file.length());

        if( is_directory(file) ) {
            cout << file << " is a directory." << endl;

            FileNode *node = new FileNode();
            node->setName(inputPath.filename());
            node->setType('d');

            root->sibling.push_back(*node);
        }
        else {
            FileNode *node = new FileNode();
            node->setName(file);
            node->setType('f');

            root->sibling.push_back(*node);
        }
    }
}
To ensure my code is always implemented correctly, the following test case must return a successful result:
  • load 1 level parent path.
  • load 2 level parent path.
  • load 3 level parent path.
  • file separator appear at the end of a path.
  • test on one file is captured without sub folder.
  • test on two files are captured without sub folder.
  • test on one files are captured when there is a sub folder.

Friday, December 1, 2017

New implementation of clearing recursive intrusive list

There is still memory leak happens at the end of each test case. Urrhhh! Now only I got to remember this is a new implementation of loading up the file path into memory. A new thing. And the clearMemory() is still implementing the old code.
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.

Monday, November 27, 2017

New solution to build parent path

It took me a few weeks to work on this POC with Boost Intrusive. I was thinking to use Boost Intrusive build a directory path. Just like a tree structure, the branches representing the files and folders, spread until the end of the sub directory. Thus the setup for this class is as follows:
class FileNode : public boost::intrusive::list_base_hook<link_mode<auto_unlink> >
{
private:
    boost::filesystem::path name; // file name
    char type; // f is file, d is directory

public:
    boost::intrusive::list< FileNode, base_hook<list_base_hook<link_mode<auto_unlink> > >, constant_time_size<false> > sibling;

};
I created a FileNode class represent the file in a path, and each object of this class can neither be a file or a folder, and the a name too. These are the private member declared in the class. The sibling member is to tell whether they are any sub directory available, if the size is greater than zero, it means there are files in it.

Now come to the main dish. There are 2 part of it; first would be the load the given path into the memory by using the class structure mention above, second is to constructed of the files underneath the given path. For this POC, I'm focusing on the first part, the second part has not yet done.

I have though should I skip the first part for some while? Say when user keyed in /home/path_1, can I just treat the value as a single FileNode? Since I doesn't really care what the value are, it would be easier for me to do the job. Coming from the perfectionism view-point, I think it would be nice to load every single file entity as a separate FileNode object. Meaning to said that /home is one object, and /path_1 is another object.

For this purpose, I create a function to handle this job for me.
FileNode* FileBot::constructParentPath(string path)
{
    vector<string> words;
    FileNode *node = new FileNode();
    string unixFilePath = path;

    boost::replace_last(unixFilePath, "/", "|");
    boost::split(words, unixFilePath, boost::is_any_of("|"), boost::token_compress_on);

    node->setType('d');
    node->setName(words[1]);

    // there is a parent node
    if( words[0] != "" ) {
        FileNode *parent = constructParentPath(words[0]);

        cout << "parent address: " << parent << endl;

        parent->sibling.push_back(*node);
    }
    else {
        fileList.push_back(*node);
        cout << "node address: " << node << " " << node->getName() << endl;
    }

    words.clear();

    return node;
}
This function is as good as it works only on Linux, but failed on Windows. It can't pass the test case in Windows specific path. After many round of rework, then only I figure out a new solution that tested out on both Linux and Windows:
int FileBot::initialize()
{
    // bail out if the path doesn't exists
    if( !exists(fileNode.getName().generic_string()) )
        return 0;

    // construct the parent path first
    string path = fileNode.getName().generic_string();
    FileNode *parent = NULL;

    typedef split_iterator<string::iterator> string_split_iterator;
    for( string_split_iterator it = make_split_iterator(path, first_finder("/", is_equal()));
         it != string_split_iterator();
         ++it)
    {
        FileNode *node = new FileNode();
        node->setType('d');
        node->setName(copy_range<string>(*it));

        cout << "value inserted: [" << copy_range<string>(*it) << "]" << endl;

        if( parent == NULL ) {
            fileList.push_back(*node);
        }
        else
            parent->sibling.push_back(*node);

        parent = node;
        cout << "parent: " << parent;
        cout << " parent value: " << parent->getName();
        cout << " sibling size: " << parent->sibling.size() << endl;
    }

    return 1;
}
The difference between the 2 solutions is that the first one is using the recursive loop and the later one is using for loop. On top of that the second solution is much easier to read than the first. To check my work is being done correctly, I have created following test case for the unit test.
/* 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
}


/* load 2 level parent path
 *
 */
BOOST_AUTO_TEST_CASE(TL_5)
{
    BOOST_TEST_MESSAGE("TC5 : load 2 level parent path");

#if defined(WIN32)
    BOOST_TEST_MESSAGE("Test path: D:/workspaceqt");
    FileBot fb("D:/workspaceqt");
#else
    BOOST_TEST_MESSAGE("Test path: /home/kokhoe");
    FileBot fb("/home/kokhoe");
#endif

    string path = "";
    if( fb.initialize() == 1 )
       path = fb.verifyFileList();

#if defined(WIN32)
    BOOST_TEST(path == "D:/workspaceqt");
    fb.clearMemory();
#else
    BOOST_TEST(path == "/home/kokhoe");
#endif
}


/* load 3 level parent path
 *
 */
BOOST_AUTO_TEST_CASE(TL_6)
{
    BOOST_TEST_MESSAGE("TC6 : load 3 level parent path");

#if defined(WIN32)
    BOOST_TEST_MESSAGE("Test path: D:/workspaceqt/ui1");
    FileBot fb("D:/workspaceqt/ui1");
#else
    BOOST_TEST_MESSAGE("Test path: /home/kokhoe/workspaceqt");
    FileBot fb("/home/kokhoe/workspaceqt");
#endif

    string path = "";
    if( fb.initialize() == 1 )
       path = fb.verifyFileList();

#if defined(WIN32)
    BOOST_TEST(path == "D:/workspaceqt/ui1");
    fb.clearMemory();
#else
    BOOST_TEST(path == "/home/kokhoe/workspaceqt");
#endif
}

Wednesday, November 8, 2017

Accessing the last element of an Intrusive list

I always thought that retrieving the last element from an intrusive list just as easy as one two three. In fact, it is not. Let's dive into the story. Here I have the intrusive list declaration:
/***** FileNode.h *****/

class FileNode : public boost::intrusive::list_base_hook<link_mode<auto_unlink> >
{
...
...

};


/***** FileBot.h *****/

typedef boost::intrusive::list<FileNode, base_hook<list_base_hook<link_mode<auto_unlink> > >, constant_time_size<false> > FileNodeListType;

class FileBot
{
private:
    FileNodeListType fileList;

...
...
};
And then I'll use the iterator as shown below go straight to access the element located at the end of the list, but somehow this a hit segmentation fault error.
        FileNodeListType::iterator it(fileList.end());

        // following piece basically doing some data manipulation
        // on the element retrieve from the list.
        FileNode *p = &*it;
        (*it).sibling.push_back(*node);

        cout << p << endl; // memory address shows 0x7ffedff8e808
The error is due to the wrong memory address is being accessed. As I verify on the element being inserted into the list (only one element is inserted in this test case) is having an address different from the one mention in the code above. Thus, according to the expert, in order to access the correct element located at the end of the list is by doing this:
        FileNodeListType::iterator it(fileList.end());
        FileNode *p = &*(--it);
        cout << p << endl; // memory address shows 0xa01bc0