【问题标题】:How to read/write std::string values from/to binary files如何从/向二进制文件读取/写入 std::string 值
【发布时间】:2010-11-23 06:17:05
【问题描述】:

我想将一个项目写入一个二进制文件,关闭它,然后再次打开它以读取它。代码简单明了,使用 Visual Studio 2008 编译和运行没有错误。

但是,使用 GCC 编译器运行时出现“段错误”。

我做错了什么?

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Item
{
private:
    string itemID;
    string itemName;
    string itemState;

public:
    Item( const string& id = "i0000", const string& name = "Zero item", const string& state = "not init" )
        : itemID( id ) , itemName( name ) , itemState( state )
    {

    }

    string& operator []( int x )
    {
        if ( 0 == x )
            return itemID;
        if ( 1 == x )
            return itemName;
        if ( 2 == x )
            return itemState;

        return ( string& )"";
    }

    const string& operator []( int x ) const
    {
        if ( 0 == x )
            return itemID;
        if ( 1 == x )
            return itemName;
        if ( 2 == x )
            return itemState;

        return ( string& )"";
    }

public:
    friend istream& operator >>( istream& i, Item& rhs )
    {
        cout << " * ItemID: ";
        getline( i, rhs.itemID );
        cout << " - Item Name: ";
        getline( i, rhs.itemName );
        cout << " - Item State: ";
        getline( i, rhs.itemState );
        return i;
    }

    friend ostream& operator <<( ostream& o, const Item& rhs )
    {
        return o << "ID = " << rhs.itemID
                 << "\nName = " << rhs.itemName
                 << "\nState = " << rhs.itemState << endl;
    }
};

void write_to_file( const string& fn, const Item& item )
{
    fstream outf( fn.c_str(), ios::binary | ios::out );
    Item temp( item );
    outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
    outf.close();
}

void read_from_file( const string& fn, Item& item )
{
    fstream inf( fn.c_str(), ios::binary | ios::in );

    if( !inf )
    {
        cout << "What's wrong?";
    }
    Item temp;
    inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
    item = temp;
    inf.close();
}

int main()
{
    string fn = "a.out";
    //Item it( "12", "Ipad", "Good" );
    //write_to_file( fn, it );


    Item temp;
    read_from_file( fn, temp );
    cout << temp;

    return 0;
}

【问题讨论】:

  • 这与你的问题无关,但是两个operator[] 函数中的两行return ( string&amp; )""未定义的行为。您正在(隐式)在 return 语句中构造一个临时的 std::string 对象,然后返回对该临时对象的引用,这是一个很大的禁忌。您应该改为返回对静态/全局对象的引用,或者更好的是,引发断言或抛出异常。
  • 非常感谢亚当。我现在明白我的问题了。

标签: c++


【解决方案1】:

两行:

outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );

inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );

错了。您正在编写对象的二进制布局,包括 std::string 实例。这意味着您正在将指针的值写入文件并将其读回。

您不能简单地从文件中读取指针并假设它们指向有效内存,特别是如果它由临时 std::string 实例持有,当它超出范围时应该释放其析构函数中的内存。我很惊讶您可以使用任何编译器“正确”运行它。

您的程序应该使用operator&lt;&lt;operator&gt;&gt; 方法写入内容并读回。它应该如下所示:

void write_to_file( const string& fn, const Item& item )
{
    fstream outf( fn.c_str(), ios::binary | ios::out );
    outf << item << std::endl;
    outf.close();
}

void read_from_file( const string& fn, Item& item )
{
    fstream inf( fn.c_str(), ios::binary | ios::in );
    if( !inf )
    {
        cout << "What's wrong?";
    }
    inf >> item;
    inf.close();
}

奖励:您的代码有一些怪癖。

幸运的是,该语句目前在您的程序中未使用(未调用该方法)。

return ( string& )"";

这是无效的,因为您将返回对临时字符串对象的引用。请记住,字符串文字 "" 不是 std::string 对象,您无法获得对 std::string&amp; 类型的引用。你可能应该提出一个例外,但你可以逃脱:

string& operator []( int x )
{
    static string unknown;
    if ( 0 == x )
        return itemID;
    if ( 1 == x )
        return itemName;
    if ( 2 == x )
        return itemState;
    return unkonwn;
}

这是一个糟糕的解决方案,因为字符串是通过引用返回的。它可以由调用者修改,因此它可能并不总是返回您认为的 "" 值。但是,它会为您的程序移除未定义的行为。

.close() 对象上的 .close() 方法调用不是必需的,当对象超出范围时,析构函数会自动调用它。插入呼叫有额外的混乱。

另外,多余的命名约定是什么?

class Item
{
private:
    string itemID;
    string itemName;
    string itemState;
// ...
};

称他们为IDnamestate 有什么问题?

【讨论】:

  • 这个回复太棒了!非常感谢安德烈,我很感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2015-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-16
相关资源
最近更新 更多