class Plaint {
std::string name, population, g; // 非 POD 類型
// ...
void show() {
fin.read((char*)&this, sizeof(Plaint)); // 錯誤用法
}
};
運行時報錯、讀出亂碼或崩潰。
std::string` 非 POD(Plain Old Data)sizeof(Plaint) 僅返回類對象本身大小(通常 24/32 字節,包含指針、長度、容量、SSO 緩衝區),不包含堆上動態分配的字符串內容。二進制寫入時只存了指針值,讀出後指針指向無效地址,導致 UB。
fin.read((char*)&this, ...) 取址錯誤this 已是 Plaint*,&this 是 Plaint**(指向指針的指針)。正確應為 (char*)this 或 (char*)&obj。但即便修正取址,因錯誤 1 仍不可行。
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));
}
};
缺點:長度固定,浪費空間或截斷長字符串。
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);
}
優點:可讀、跨平台、跨語言、版本兼容性強。
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);
}
優點:緊湊、高效、支援任意長度、易於擴展字段。
| 錯誤模式 | 正確替代 |
|---|---|
類含 std::string/vector/map 直接 read/write(this, sizeof) | 實現序列化函數或用序列化庫 |
&this 取址 | (char*)this 或 (char*)&obj |
假設 sizeof(Class) 含動態數據 | 理解 POD 與非 POD 區別 |
| 忽略大端/小端、對齊、編譯器 ABI 差異 | 跨平台必須採用標準序列化格式 |
C++ 結構體二進制讀寫僅限 POD 類型。含 std::string 等非 POD 成員時,務必實現顯式序列化/反序列化,或引入成熟庫。切記:內存佈局 ≠ 存儲格式。