首页 文章

带指针和二进制文件的类

提问于
浏览
-2

好吧,伙计们,我已经问了这个,但我觉得我没有解释好,我找不到解决方案,所以我会再次询问更多细节,并解释更多我的问题的背景 .

我有两个包含用户数据的类,我想将它们保存在二进制文件中 . 另一方面,我有一个模板类负责保存这些类 .

有一个非常重要的事实,我必须提到:在开始时,我选择编码一个辅助类,我会保存任何类 . 该辅助类负责写入/读取数据 . 原始类具有字符串成员,辅助类具有指向char的指针 . 但是最近,为了寻求更多的简单性和灵活性,我选择组合原始类,它包含字符串类的好处;它的辅助具有指针,使得类在保存时更加舒适 . 因此,我有一个类处理数据的输入/输出和数据的写/读,而不是有两个类 .

此更改看起来像这样:

class AuxNOTE;

//Original Class: Input/Output of Data
class NOTE{
private:
    string _Category;
    string _Description;
public:
    NOTE() : _Category( "" ) , _Description( "" ) { }

    NOTE( const NOTE & note ) : _Category( note._Category ) 
                              , _Description( note._Description ) { }

    NOTE( string category , string description ) : _Category( category)                                                    
                                                 , _Description( description ) { }

    NOTE( const AuxNOTE & aux ) : _Category( aux._Category ) 
                                , _Description( aux._Description ) { }

    NOTE & operator=( const NOTE & note ){ 
         _Category = note._Category;
         _Description = note._Description;
         return *this;
}

    NOTE & operator=( const AuxNOTE & aux ){
         _Category = string( aux._Category );
         _Description = string( aux._Description );
         return *this;
}

    string GetCategory() const { return _Category; }
    string GetDescription() const { return _Description; }
    void SetCategory( string category ) { _Category = category; }
    void SetDescription( string description ) { _Description = description; }
}; 

//Auxliary Class: Writing/Reading of Data to/from binary files
class AuxNOTE{
private:
     char _Category[50];
     char _Description[255];
public:
     AuxNOTE(){ }

     AuxNOTE( const NOTE & note ){
          strcpy( _Category , note._Category );
          strcpy( _Description , note._Description);
     }
     AuxNOTE & operator=( const NOTE & note ){
          strcpy( _Category , note._Category );
          strcpy( _Description , note._Description );
          return *this;
     }
};

我现在拥有的是这样的:

//Class NOTE: Input/Output of Data and Writing/Reading to/from binary files.
// .h file
class NOTE{
private:
   char * _Category;
   char * _Description;
public:
   NOTE();
   NOTE( const NOTE & note );
   NOTE( string category , string description );
   NOTE & operator=( const NOTE & note )

   string GetCategory() const;
   string GetDescription() const;
   void SetCategory( string category );
   void SetDescription( string description );
};

// .cpp file
#include "NOTE.h"

NOTE :: NOTE() : _Category( nullptr ) ,_Description( nullptr )
{

}

NOTE :: NOTE( string description , string category )
     : _Category ( new char[ category.size() + 1 ] )
     , _Categoria( new char[ description.size() + 1 ] )
{
    strcpy( _Categoria , category.c_str() );
    strcpy( _Descripcion , description.c_str() );
}

NOTE :: NOTE (const NOTE & copy )
     : _Category( nullptr )
     , _Description nullptr )
{
    if( copy._Description != nullptr ){
        _Description =  new char[ strlen( copy._Description ) + 1 ];
        strcpy( _Description , copy._Description );
    }

    if( copy._Category != nullptr ){
        _Category = new char[ strlen( copy._Category ) + 1 ];
        strcpy( _Category , copy._Category );
    }
}

NOTE :: ~NOTE() {
    if( _Description != nullptr ) delete [] _Description;
    if( _Category != nullptr ) delete [] _Category;
}

//Get Methods
string NOTE :: GetDescription() const { return string(_Description); }

string NOTE :: GetCategory() const { return string(_Category); }

//Set Methods
void NOTE :: SetDescription( string description ){

    if( _Description != nullptr ) delete [] _Description;
    _Description = new char[ description.size() + 1 ];
    strcpy( _Description , description.c_str() );
}

void NOTE :: SetCategory( string category ){

    if( m_Category != nullptr ) delete [] _Category;
    _Category = new char[ category.size() + 1 ];
    strcpy( _Category , category.c_str() );
}

//Operators
NOTE & NOTE :: operator=( const NOTE & note ){
    if( note._Description != nullptr ) SetDescription( note.GetDescription() );
    if( note._Category != nullptr ) SetCategory( note.GetCategory() );
    return *this;
}

请注意,如果NOTE类适用于字符串成员,那么公共接口看起来就好了,但它没有,因为它适用于指向char的指针 . 因此,可以毫无问题地保存NOTE类 . 但是,该类在编写/读取时并不负责,但我创建了另一个可以保存任何类的类,只要这些类具有可以保存的成员即可 .

负责这个的类是一个模板类,看起来像这样:

template< class T >
class SAVER{
private:
   vector< T > _Vector;
   string _File;
public:
   SAVER( string file );
   ~SAVER();
};


template< class T >
SAVER< T > :: SAVER( string file ) : _File( file ){

    assert( _File != "" );

    ifstream file( _File , ios::binary );

    if( file.is_open() ){

        T obj;
        while( file.read( reinterpret_cast<char*>(&obj) , sizeof(obj) ) )
            _Vector.push_back( obj );
    }
}


template< class T >
Saver< T > :: ~Saver() {

    if( _Vector.empty() )
           return;

    ofstream file( _File , ios::binary | ios::trunc );  
    assert( file.is_open() );

    auto itr = _Vector.begin();
    auto end = _Vector.end();

    while( itr != end ){
        if ( !file.write( reinterpret_cast<char*>( &itr ) , sizeof(itr) ) ) 
           break;
        itr++;
     }
}

SAVER的构造函数处理读取并将数据(例如NOTE对象)放入其向量中 . 驱逐舰处理将所有矢量对象写入相应的二进制文件 .

我得说清楚我的错误不是编译错误,但它们是运行时错误 .

现在,这是我遇到的问题:

当我执行整个程序时,它必须读取二进制文件但它会中断 . 我用调试器打开它,我看到程序在这行中完成了“分段错误错误”,这来自SAVER构造函数:

NOTE :: ~NOTE() {
    if( _Description != nullptr ) delete [] _Description; //It breaks at this line
    if( _Category != nullptr ) delete [] _Category;
}

在调试器中,我可以看到_Description的值,然后在它旁边出现一个内存错误,上面写着:错误:无法访问地址处的内存(_Description的值) .

为什么会这样?你看到有什么错误吗?如果您需要更多信息或者您不理解某些内容,请告诉我 .

2 回答

  • 1

    首先,在互联网上搜索"c++ serialization library" . 您正在执行的操作称为序列化 .

    指针和包含指针的任何类都不能逐字写入文件 . 指针是内存中的位置 . 大多数操作系统无法保证您的程序在下次执行时将具有确切的内存位置 . 您的程序可能在不同的内存区域运行,这会改变数据的存储位置 .

    有一些技术可以解决这个问题,例如先写入数量,然后再写入数据,或者将数据写入某种哨兵(例如C-Style字符串中的'\ 0') .

    考虑不要写为二进制文件,而是使用格式化的文本表示 . 许多平台将读入一个数字并转换为本机表示 . 以二进制模式写入文件的本机表示,许多在另一个平台上不相同(查找“Endianess”) . 此外,大多数文本编辑器和文字处理器都可以轻松读取文本文件 . 读取和解释二进制文件更加困难 .

    除非您的应用程序的瓶颈受I / O限制且I / O时序至关重要,否则请考虑使用数据的文本表示 . 它更容易阅读(特别是在调试程序时)并且易于携带 .

  • 1

    在调试器中,我可以看到_Description的值,然后在它旁边出现一个内存错误,上面写着:错误:无法访问地址处的内存(_Description的值) .

    当然,你不能反序列化二进制文件中的指针 . 您需要将其大小信息和内容存储在文件中 .

相关问题