You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二进制文件读取Player数据崩溃,拷贝赋值与容器存储问题咨询

问题解答

Q1:拷贝赋值运算符的问题

你的拷贝赋值运算符存在两处严重问题:

  1. 核心成员未同步:当前代码只处理了p指针,完全忽略了name、score、id、num这些成员变量,赋值后对象的核心状态不会被更新,导致数据不一致。
  2. 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);
    }

    // 后续操作...
}

第三步:实现排序与搜索

排序

有两种常用方式:

  1. 重载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());
  1. 自定义比较函数:支持多种排序规则,比如按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 04:14:55