简体   繁体   English

向二进制文件写入/读取std :: set <T>

[英]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. 我正在尝试编写一对写入/读取函数,分别用于将std::set< T >数据容器存储到二进制文件中/从二进制文件中检索数据。 My writeSet() function appears to work as desired, and stores std::set< T > data containers without any apparent problems. 我的writeSet()函数似乎可以正常工作,并存储std::set< T >数据容器,而没有任何明显的问题。 However the readSet() function does not, and throws an "Unhandled exception [...] Access violation reading location 0xFEEEFEF6." 但是, readSet()函数不会,并且会抛出“未处理的异常访问冲突读取位置0xFEEEFEF6”。 exception AFTER the main() function returns EXIT_SUCCESS . main()函数返回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. 就我所能调试的(使用Visual Studio 2013)而言, readSet()实际上确实可以成功读取二进制文件并将数据正确分配给所寻址的std::set< T >数据容器。 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. VS2013崩溃时,它为我提供了中断程序执行的机会,并指出xtree.h头文件中的错误。 Specifically the debugger complains about _Pnext the line || _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr) 具体地说,调试器抱怨_Pnext|| _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr) || _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr) of the following section: || _Ptr != 0 && (*_Pnext)->_Ptr != _Ptr)

 #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 writeSet() :将std :: set <T>写入二进制文件

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 readSet() :从二进制文件读取std :: set <T>

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 main() :最小的main函数,该函数再现“未处理的异常”错误

#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? 是您所有的T POD吗? 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. 此外,数据集管理被保存在由管理动态分配的内存set ,而不是在set本身。
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 ! 附带说明一下, std::string对于字符串连接而言工作得很好,不需要拆散std::stringstream

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

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