简体   繁体   中英

Write/read std::set< T > to/from binary file

I am trying to code a write/read pair of functions with which to respectively store/retrieve a std::set< T > data container into/from a binary file. My writeSet() function appears to work as desired, and stores std::set< T > data containers without any apparent problems. However the readSet() function does not, and throws an "Unhandled exception [...] Access violation reading location 0xFEEEFEF6." exception AFTER the main() function returns EXIT_SUCCESS .

As far I can debug (using Visual Studio 2013), readSet() does in fact seem to successfully read binary files and correctly allocates data to the addressed std::set< T > data container. When VS2013 crashes, it offers me the opporutity to break the program execution, and points me to an error in the xtree.h header file. Specifically the debugger complains about _Pnext the line || _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr) || _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr) of the following section:

 #if _ITERATOR_DEBUG_LEVEL == 2
    void _Orphan_ptr(_Myt& _Cont, _Nodeptr _Ptr) const
        {   // orphan iterators with specified node pointers
        _Lockit _Lock(_LOCK_DEBUG);
        const_iterator **_Pnext = (const_iterator **)_Cont._Getpfirst();
        if (_Pnext != 0)
            while (*_Pnext != 0)
                if ((*_Pnext)->_Ptr == this->_Myhead
                    || _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr)
                    _Pnext = (const_iterator **)(*_Pnext)->_Getpnext();
                else
                    {   // orphan the iterator
                    (*_Pnext)->_Clrcont();
                    *_Pnext = *(const_iterator **)(*_Pnext)->_Getpnext();
                    }  

My minimal working solution is as follows:

writeSet() : Writes std::set< T > into binary file

template < class T >
void writeSet(const std::string& filePath, const std::string fileName, std::set<T>& data)
{
    // Construct binary file location string using filePath and fileName inputs
    std::stringstream file; file << filePath.c_str() << "/" << fileName.c_str();
    std::ofstream fileStream; fileStream.open(file.str().c_str(), std::ios::out | std::ios::binary); 

    // First write number of std::set elements held by data, and then write std::set block to binary file
    std::set<T>::size_type n = data.size(); 
    fileStream.write(reinterpret_cast<char*>(&n), sizeof(std::set<T>::size_type));
    fileStream.write(reinterpret_cast<char*>(&data), sizeof(T)*n); 
    fileStream.close();
}

readSet() : Reads std::set< T > from binary file

template < class T >
void readSet(const std::string& filePath, const std::string fileName, std::set<T>& data)
{
    // Construct binary file location string using filePath and fileName inputs
    std::stringstream file; file << filePath.c_str() << "/" << fileName.c_str();
    std::ifstream fileStream; fileStream.open(file.str().c_str(), std::ios::in | std::ios::binary); 


    // First read number of elements stored in binary file, then write file content to adresses std::set data variable
    std::set<T>::size_type n; 
    fileStream.read(reinterpret_cast<char*>(&n), sizeof(std::set<T>::size_type));
    fileStream.read(reinterpret_cast<char*>(&data), sizeof(T)*n); 
    fileStream.close();
}

main() : Minimal main function which reproduces the "Unhandled exception" error

#include <fstream>
#include <iostream>
#include <set>
#include <sstream>
#include <string>

int main()
{
    // Define binary file read/write directory
    const std::string path("C:/data");

    // writeSet() testing...
    std::set<int> writeSetData;
    writeSetData.insert(1); writeSetData.insert(3);
    writeSetData.insert(0); writeSetData.insert(2);

    writeSet(path, "binaryFile", writeSetData);

    // readSet() testing...
    std::set<int> readSetData;
    readSet(path, "binaryFile", readSetData);

    std::cout << "readSetData= {";
    for (std::set<int>::iterator it = readSetData.begin(); it != readSetData.end(); ++it){
        std::cout << *it << ", ";
    } std::cout << "}" << std::endl;

    return EXIT_SUCCESS;
}

Are all your T s PODs? Otherwise, making a binary copy is just about meaningless, instead of creating a semantic copy.
Also, the data the set managed is saved in dynamically allocated memory managed by the set , not in the set itself.
As a third point, that space does not magically grow or shrink whenever you try to write an arbitrary amount of elements there.
You have to ask the set to grow by inserting elements manually!

As a side-note, std::string works perfectly fine for string concatenations, there's no need to break out the std::stringstream !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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