首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ read 讀取二進制文件失敗:string 非 POD 類型不可直接二進制讀寫

     編輯:程式設計綜合問答

錯誤現場


class Plaint {
    std::string name, population, g; // 非 POD 類型
    // ...
    void show() {
        fin.read((char*)&this, sizeof(Plaint)); // 錯誤用法
    }
};

運行時報錯、讀出亂碼或崩潰。

兩大核心錯誤

1. std::string` 非 POD(Plain Old Data)

sizeof(Plaint) 僅返回類對象本身大小(通常 24/32 字節,包含指針、長度、容量、SSO 緩衝區),不包含堆上動態分配的字符串內容。二進制寫入時只存了指針值,讀出後指針指向無效地址,導致 UB。

2. fin.read((char*)&this, ...) 取址錯誤

this 已是 Plaint*,&this 是 Plaint**(指向指針的指針)。正確應為 (char*)this 或 (char*)&obj。但即便修正取址,因錯誤 1 仍不可行。

正確方案:序列化而非內存映像

方案 A:固定長度字符陣列(最接近二進制結構體)


struct Plaint {
    char name[64];
    char population[64];
    char g[64];
    // 現在是 POD,可直接二進制讀寫
    void write(std::ofstream& fout) const {
        fout.write((const char*)this, sizeof(*this));
    }
    void read(std::ifstream& fin) {
        fin.read((char*)this, sizeof(*this));
    }
};

缺點:長度固定,浪費空間或截斷長字符串。

方案 B:文本格式(CSV/JSON/自定義文本協議)


void write(std::ofstream& fout) const {
    fout << name << '|' << population << '|' << g << '\n';
}
void read(std::ifstream& fin) {
    std::getline(fin, name, '|');
    std::getline(fin, population, '|');
    std::getline(fin, g);
}

優點:可讀、跨平台、跨語言、版本兼容性強。

方案 C:二進制長度前綴編碼(高效且變長)


void write(std::ofstream& fout) const {
    auto writeStr = [&](const std::string& s) {
        uint32_t len = s.size();
        fout.write((const char*)&len, sizeof(len));
        fout.write(s.data(), len);
    };
    writeStr(name);
    writeStr(population);
    writeStr(g);
}
void read(std::ifstream& fin) {
    auto readStr = [&](std::string& s) {
        uint32_t len;
        fin.read((char*)&len, sizeof(len));
        s.resize(len);
        fin.read(&s[0], len);
    };
    readStr(name);
    readStr(population);
    readStr(g);
}

優點:緊湊、高效、支援任意長度、易於擴展字段。

方案 D:成熟序列化庫(生產級推薦)

  • Protocol Buffers (protobuf):Schema 定義、多語言、向前/向後兼容。
  • cereal / Boost.Serialization:C++ 原生、支援 STL 容器、版本控制。
  • FlatBuffers / MessagePack:零拷貝/高壓縮比。

避坑檢查表

錯誤模式正確替代
類含 std::string/vector/map 直接 read/write(this, sizeof)實現序列化函數或用序列化庫
&this 取址(char*)this 或 (char*)&obj
假設 sizeof(Class) 含動態數據理解 POD 與非 POD 區別
忽略大端/小端、對齊、編譯器 ABI 差異跨平台必須採用標準序列化格式

結語

C++ 結構體二進制讀寫僅限 POD 類型。含 std::string 等非 POD 成員時,務必實現顯式序列化/反序列化,或引入成熟庫。切記:內存佈局 ≠ 存儲格式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved