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

使用std::sort排序结构体vector触发读取访问违例求助

问题排查与解决方案

嘿,我一眼就揪出了导致你崩溃的元凶——你对包含std::string的结构体的二进制读写方式完全错误,这才让排序时触发了读取访问违例!

核心问题分析

你的Highscore结构体里包含std::string name,而std::string是一个非平凡类型:它内部并不是直接存储字符串内容,而是保存了指向堆内存的指针、字符串长度等元数据。当你用下面这段代码直接读写整个结构体时:

in.read((char*)&_highscores[0], _highscores.size() * sizeof(Highscore));

你实际上只是把std::string里的指针地址、长度这些值写入了文件。当你从文件读回来时,这些指针指向的内存早就被释放(或者是完全无效的垃圾地址)了。

虽然你重载的operator<只比较points字段,但std::sort在排序过程中会频繁移动、拷贝容器里的元素——这个过程会触发std::string的析构、拷贝构造或移动构造,而这些操作都会访问到无效的指针,直接导致内存访问违例(也就是你看到的_Pnext was 0x217AE3EE9D8错误)。

解决方案:正确序列化/反序列化结构体

你需要手动逐个字段处理Highscore的读写,不能直接整块内存拷贝。下面是修复后的代码示例:

1. 修复读取逻辑(loadFromFile)

bool HighscoreManager::loadFromFile() {
    std::ifstream in(FileName, std::ios::in | std::ios::binary);
    if(!in) {
        return false;
    }

    try {
        std::vector<Highscore>::size_type size = 0;
        // 先读取元素数量
        in.read(reinterpret_cast<char*>(&size), sizeof(size));
        if (!in) {
            return false;
        }

        _highscores.clear();
        _highscores.reserve(size);

        for (std::vector<Highscore>::size_type i = 0; i < size; ++i) {
            int rank = 0;
            int points = 0;
            // 读取rank
            in.read(reinterpret_cast<char*>(&rank), sizeof(rank));
            // 读取字符串长度
            std::string::size_type name_len = 0;
            in.read(reinterpret_cast<char*>(&name_len), sizeof(name_len));
            // 读取字符串内容
            std::string name(name_len, '\0');
            in.read(&name[0], name_len);
            // 读取points
            in.read(reinterpret_cast<char*>(&points), sizeof(points));

            if (!in) {
                _highscores.clear();
                return false;
            }

            _highscores.emplace_back(rank, std::move(name), points);
        }
    } catch(const std::exception& e) {
        std::cout << e.what() << std::endl;
        _highscores.clear();
        return false;
    }

    sortAndChangeRanks(false);
    return true;
}

2. 配套的写入逻辑(补上你需要的saveToFile)

bool HighscoreManager::saveToFile() {
    std::ofstream out(FileName, std::ios::out | std::ios::binary | std::ios::trunc);
    if(!out) {
        return false;
    }

    try {
        std::vector<Highscore>::size_type size = _highscores.size();
        // 写入元素数量
        out.write(reinterpret_cast<const char*>(&size), sizeof(size));

        for (const auto& hs : _highscores) {
            // 写入rank
            out.write(reinterpret_cast<const char*>(&hs.rank), sizeof(hs.rank));
            // 写入字符串长度
            std::string::size_type name_len = hs.name.size();
            out.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len));
            // 写入字符串内容
            out.write(hs.name.data(), name_len);
            // 写入points
            out.write(reinterpret_cast<const char*>(&hs.points), sizeof(hs.points));
        }
    } catch(const std::exception& e) {
        std::cout << e.what() << std::endl;
        return false;
    }

    return out.good();
}

额外的小建议

  • 检查你的operator<逻辑:你现在是按points升序排序(分数低的在前),如果你的排行榜需要分数高的排前面,应该改成:
    bool operator<(const Highscore& h1) const {
        return points > h1.points; // 降序排序
    }
    
  • 文件操作时尽量依赖RAII(比如std::ifstream/std::ofstream的析构自动关闭文件),不要手动调用close(),除非你需要立即检查关闭结果。

内容的提问来源于stack exchange,提问作者Janfiderheld

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 22:42:57