2010-11-23 14 views
4

バイナリファイルに項目を書き込んで閉じ、もう一度開いて読み込みたいとします。コードはシンプルでわかりやすく、Visual Studio 2008を使用してコンパイルしてエラーなく実行しました。バイナリファイルからstd :: string値を読み書きする方法

ただし、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; 
} 
+1

これはあなたの問題とは無関係ですが、2つの 'operator []'関数の 'return(string&)" "という行は**未定義の動作**です。あなたは(暗黙的に)return文で一時的な 'std :: string'オブジェクトを構築してから、その一時的な参照を返します。これは大きなno-noです。静的/大域オブジェクトへの参照を返すか、アサーションを生成するか例外をスローする方がよいでしょう。 –

+0

アダムに感謝します。私は今問題を理解しています。 – Chan

答えて

9

二行:

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

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

は間違っています。 std::stringインスタンスを含む、オブジェクトのバイナリレイアウトを作成しています。これは、ファイルへのポインタの値を書き込んで、それらを読み戻すことを意味します。

ファイルからポインタを読み取って、有効なメモリを指しているとは限りません。特に、範囲外になったときにそのデストラクタのメモリを解放するはずの一時的なstd::stringインスタンスによって保持されている場合私はあなたがこれをどんなコンパイラでも "正しく"動かすことに驚いています。

あなたのプログラムは、あなたのoperator<<operator>>メソッドを使って内容を書き込んで読み返すべきです。それは次のようになります。

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(); 
} 

BONUS:あなたのコードを持ついくつかの癖があります。

このステートメントは、ありがたいことに、あなたのプログラムで現在使用されていません(このメソッドは呼び出されません)。

return (string&)""; 

一時的な文字列オブジェクトへの参照を返すので無効です。文字列リテラル""std::stringオブジェクトではなく、タイプstd::string&の参照を取得できません。おそらく、例外を発生させる必要がありますが、あなたが離れて得ることができる:

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

これは、文字列は参照で返されることを考えると貧弱なソリューションです。これは発信者によって変更される可能性があるので、必ず""の値を返すとは限りません。ただし、プログラムの未定義の動作は削除されます。

std::fstreamオブジェクトのメソッド呼び出しは不要です。デストラクタは、オブジェクトがスコープから外れると自動的に呼び出します。コールを挿入するには余分な混乱があります。

また、冗長な命名規則は何ですか? IDnamestateそれらを呼び出すと間違って何

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

+0

これはすばらしい返信です! Andre、私はそれを感謝します。 – Chan

+0

思い出してくれてありがとう、私は本当に知りませんでした。 – Chan

関連する問題