【问题标题】:Write/read std::set< T > to/from binary file向/从二进制文件写入/读取 std::set< T >
【发布时间】:2014-12-12 00:09:58
【问题描述】:

我正在尝试编写一对写/读函数,分别用于在二进制文件中存储/检索std::set&lt; T &gt; 数据容器。我的writeSet() 函数似乎可以正常工作,并且可以毫无问题地存储std::set&lt; T &gt; 数据容器。但是readSet() 函数没有,并抛出“未处理的异常 [...] 访问冲突读取位置 0xFEEEEF6”。 main() 函数返回 EXIT_SUCCESS 之后的异常。

据我调试(使用 Visual Studio 2013),readSet() 实际上似乎成功读取二进制文件并将数据正确分配到寻址的std::set&lt; T &gt; 数据容器。当 VS2013 崩溃时,它为我提供了中断程序执行的机会,并指出 xtree.h 头文件中的错误。具体来说,调试器抱怨_Pnext 以下部分的|| _Ptr != 0 &amp;&amp; (*_Pnext)-&gt;_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();
                    }  

我的最小工作解决方案如下:

writeSet() : 将 std::set 写入二进制文件

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

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

#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;
}

【问题讨论】:

    标签: c++ set std binaryfiles


    【解决方案1】:

    您的所有Ts POD 都是吗?否则,制作二进制副本几乎没有意义,而不是创建语义副本。
    此外,集合管理的数据保存在由set 管理的动态分配内存中,而不是set 本身。
    第三点,当您尝试在其中写入任意数量的元素时,该空间不会神奇地增长或缩小。
    您必须通过手动插入元素来要求集合增长!

    作为旁注,std::string 非常适合字符串连接,没有必要打破std::stringstream

    【讨论】:

    • 这是正确的,但是我将扩展答案,因为它可能难以理解。集合类仅包含管理分配给该类的数据所需的数据和功能。它不包含分配的数据本身。一个集合可能由几个指针和整数组成。要将 set 类管理的数据存储到二进制文件中,您需要遍历该容器并将各个条目写入二进制文件。要读回这些数据,您需要从二进制文件中读取这些数据并将它们单独添加到集合中。
    • 感谢 Deduplicator 和 kkurylo;在为 std::vector 数据容器(数据串行存储的地方)编写了一对类似的读/写函数后,我被带走了,忘记了 std:set 容器是树......感谢您的提示!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多