二进制文件读取Player数据崩溃,拷贝赋值与容器存储问题咨询
问题解答
Q1:拷贝赋值运算符的问题
你的拷贝赋值运算符存在两处严重问题:
- 核心成员未同步:当前代码只处理了
p指针,完全忽略了name、score、id、num这些成员变量,赋值后对象的核心状态不会被更新,导致数据不一致。 - unique_ptr所有权冲突:
p.reset(rhs.p.get())是致命错误——unique_ptr的reset会接管传入的指针,但rhs.p仍持有该内存的所有权,最终两个unique_ptr会指向同一块内存,析构时重复释放内存,直接触发abort()错误。
正确实现方式
推荐使用copy-and-swap手法,简洁且安全:
Player& operator=(const Player& rhs) { if (this != &rhs) { Player temp(rhs); // 利用拷贝构造完成全成员复制 swap(*this, temp); // 交换资源,临时对象析构时自动清理旧资源 } return *this; }
也可以手动实现复制逻辑:
Player& operator=(const Player& rhs) { if (this == &rhs) return *this; // 复制基础成员 name = rhs.name; score = rhs.score; id = rhs.id; num = rhs.num; // 重新分配内存并拷贝数据 p = make_unique<char[]>(num); memcpy(p.get(), rhs.p.get(), num); return *this; }
Q2:存入容器并实现排序与搜索
首先要解决二进制读写的根本错误:你当前的write()和read()直接读写整个Player对象的内存布局,而Player包含std::string、std::unique_ptr这类非POD类型,它们的内部指针指向堆内存,写入文件的是无效的指针地址,读取后会导致非法内存访问,这也是程序abort()的核心原因之一。
第一步:修正序列化/反序列化逻辑
必须手动序列化每个成员的实际数据,而非直接读写对象内存:
// 修正后的write函数 void write(ostream& os) { // 序列化std::string:先写长度,再写内容 size_t name_len = name.size(); os.write(reinterpret_cast<char*>(&name_len), sizeof(name_len)); os.write(name.data(), name_len); // 序列化基础类型 os.write(reinterpret_cast<char*>(&score), sizeof(score)); os.write(reinterpret_cast<char*>(&id), sizeof(id)); os.write(reinterpret_cast<char*>(&num), sizeof(num)); // 序列化p指向的数据 os.write(p.get(), num); } // 修正后的read函数(添加返回值判断读取状态) bool read(istream& is) { // 反序列化std::string size_t name_len; if (!is.read(reinterpret_cast<char*>(&name_len), sizeof(name_len))) return false; name.resize(name_len); if (!is.read(&name[0], name_len)) return false; // 反序列化基础类型 if (!is.read(reinterpret_cast<char*>(&score), sizeof(score))) return false; if (!is.read(reinterpret_cast<char*>(&id), sizeof(id))) return false; if (!is.read(reinterpret_cast<char*>(&num), sizeof(num))) return false; // 反序列化p指向的数据 p = make_unique<char[]>(num); return is.read(p.get(), num).good(); }
第二步:存入vector容器
修正读写逻辑后,优化读取循环(避免peek() != EOF的误判问题):
int main() { ifstream in{ "player files", ios::binary }; if (!in) { return 0; } vector<Player> players; Player temp; while (temp.read(in)) { players.push_back(temp); } // 后续操作... }
第三步:实现排序与搜索
排序
有两种常用方式:
- 重载
operator<定义默认规则:比如按分数降序、名字升序排序
bool operator<(const Player& rhs) const { if (score != rhs.score) return score > rhs.score; return name < rhs.name; } // 使用时直接调用sort sort(players.begin(), players.end());
- 自定义比较函数:支持多种排序规则,比如按ID升序
bool compareById(const Player& a, const Player& b) { return a.getId() < b.getId(); } // 使用时传入比较函数 sort(players.begin(), players.end(), compareById);
搜索
- 线性搜索:适合未排序容器,依赖你已实现的
operator==
// 构造搜索目标 Player target; target.setName("Alice"); target.setScore(95); auto it = find(players.begin(), players.end(), target); if (it != players.end()) { // 找到目标对象 }
- 二分搜索:适合已排序容器,效率更高
// 假设已按分数降序排序,搜索分数为100的玩家 auto it = lower_bound(players.begin(), players.end(), Player{}, [](const Player& a, const Player& b) { return a.getScore() > b.getScore(); // 匹配排序规则的比较逻辑 }); if (it != players.end() && it->getScore() == 100) { // 找到目标对象 }
内容的提问来源于stack exchange,提问作者jade808
相关产品推荐
相关产品推荐

