C++ - 对具有 std::sort 的结构向量进行排序会导致读取访问冲突

C++ - Sorting vector of structs with std::sort results in read access violation

我对 std::sort 方法有疑问。在下面的代码中,我使用 std::sort 方法对结构向量(= Highscore)进行排序。但是,当我 运行 这一行时,xmemory 文件中会抛出一个 "read access violation" 异常。

详情如下: 抛出异常:读取访问冲突。 _Pnext 是 0x217AE3EE9D8。发生

这是错误发生的方法。

void HighscoreManager::sortAndChangeRanks(bool deleteLast) {
    std::sort(_highscores.begin(), _highscores.end());
    if (deleteLast && _highscores.size() > MaxHighscores) {
        _highscores.pop_back();
    }

    for (int i = 0; i < _highscores.size(); i++) {
        _highscores.at(i).rank = i + 1;
    }
}

_highscores 定义为 std::vector<Highscore> _highscores; 并在方法调用之前填充了文件中的值。这很好用。当我在使用排序方法之前进行调试时,向量中会填充文件中的正确值。

这是高分结构的实现:

struct Highscore {
    int rank;
    std::string name;
    int points;

    Highscore() {}

    Highscore(int r, std::string n, int p) : rank(r), name(std::move(n)), points(p) {}

    bool operator<(const Highscore& h1) const {
        return points < h1.points;
    }
};

请帮助我或指出错误所在的方向,我没有想法。

编辑

由于在调用 std::sort 之前在评论中询问了向量在哪里使用,因此这是从对象构造函数调用的方法,并且是唯一一次在排序之前使用向量。这种从二进制文件读取(写入工作类似)的方式是基于 .

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((char*)&size, sizeof(size));
        _highscores.resize(size);
        in.read((char*)&_highscores[0], _highscores.size() * sizeof(Highscore));        
    } catch(const std::exception& e) {
        std::cout << e.what() << std::endl;
    }

    in.close();
    sortAndChangeRanks(false);
    return in.good();
}

不知道你们的高分存储“优化”了什么。这似乎只是白费力气。您不会存储数百万的高分。您可以将它们存储为文本。 “优化”无法在正常使用中衡量。如果您认为自己正在优化:显示测量结果。否则你就是在自欺欺人,浪费时间。

最重要的是,您已将代码复杂化到 运行 成为一个需要很长时间调试的问题。那是一种学习经历,但严格来说,你因此浪费了更多时间。在大多数情况下,您的时间比运行时间花费更多。

您所需要的只是可以在两分钟内完成的琐碎文本流 I/O。如果您不完全了解正在发生的事情,则不建议您随意使用二进制存储。就目前而言,如果您尝试读取在具有不同字节顺序的机器上编写的高分,您的代码将会崩溃或更糟。现在你必须管理所有数字数据的字节序……祝你好运。

无论如何,这实际上是一种悲观情绪,因为您不断地重新分配临时字符串缓冲区。不需要那个缓冲区。您应该调整字符串本身的大小并将数据放入其中。

std::string name(nLen);
in.read(&name[0], name.size());

这是我目前使用的解决方案。这对我有用并解决了我的问题,即 reading/writing 和 std::string 到二进制文件而不是排序方法(感谢对问题的评论!)。为了解决这个问题,我使用了 this.

的部分内容

正在从文件中读取:

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

    try    {
        std::vector<Highscore>::size_type size = 0;
        in.read((char*)&size, sizeof(size));
        for(int i = 0; i < size; i++) {
            int r, p;
            size_t nLen;
            in.read((char*)&r, sizeof(int));
            in.read((char*)&p, sizeof(int));
            in.read((char*)&nLen, sizeof(size_t));

            char* temp = new char[nLen + 1];
            in.read(temp, nLen);
            temp[nLen] = '[=10=]';
            std::string name = temp;
            delete[] temp;

            _highscores.emplace_back(r, name, p);
        }
    } catch(const std::exception& e) {
        std::cout << e.what() << std::endl;
    }

    in.close();
    sortAndChangeRanks(false);
    return in.good();
}

写入文件:

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

    std::vector<Highscore>::size_type size = _highscores.size();
    try {
        out.write((char*)&size, sizeof(size));
        for(int i = 0; i < size; i++) {
            out.write((char*)&_highscores.at(i).rank, sizeof(int));
            out.write((char*)&_highscores.at(i).points, sizeof(int));
            size_t nameLen = _highscores.at(i).name.size();
            out.write((char*)&nameLen, sizeof(size_t));
            out.write((char*)_highscores.at(i).name.c_str(), nameLen);
        }
    } catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    out.close();

    return out.good();
}

谢谢大家的帮助!