C++ - 使用 std::sort 对结构向量进行排序导致读取访问冲突
Posted
技术标签:
【中文标题】C++ - 使用 std::sort 对结构向量进行排序导致读取访问冲突【英文标题】:C++ - Sorting vector of structs with std::sort results in read access violation 【发布时间】:2020-06-09 10:42:57 【问题描述】:我对 std::sort 方法有疑问。在以下代码中,我使用 std::sort 方法对结构向量进行排序(= Highscore)。但是,当我运行此行时,xmemory 文件中会引发“读取访问冲突”异常。
以下是详细信息: 抛出异常:读取访问冲突。 _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;
,并在方法调用之前填充了来自文件的值。这工作得很好。当我在使用排序方法之前进行调试时,向量会被文件中的正确值填充。
这是 Highscore-struct 的实现:
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 之前在 cmets 中询问了向量在哪里使用,因此这是从对象构造函数调用的方法,也是唯一一次在排序之前使用向量。这种从二进制文件中读取(写入工作类似)的方式是基于this。
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();
【问题讨论】:
嗯,循环本身并不是天生错误的。问题出在循环的_highscores.at(i)
部分。
你需要这样改:for (int i = 0; i < _highscores.size(); i++)
.
感谢您的帮助,您当然是对的!但这对我的问题没有帮助,因为 std::sort 的行在循环之前。
in.read((char*)&_highscores[0], _highscores.size() * sizeof(Highscore));
- 这不是反序列化非平凡类的方式。你的班级有一个std::string
,其中包含可变数量的char
s。您的 sizeof(Highscore)
是静态的。看到问题了吗? This might help
@Ted Lyngmo & Yksisarvinen 谢谢你的支持帮助我解决了这个问题!它现在可以正常工作了:)
【参考方案1】:
我不知道您的高分存储有哪些“优化”。这似乎只是白费力气。您没有存储数百万的高分。您可以将它们存储为文本。 “优化”在正常使用中无法衡量。如果您认为自己正在优化:显示测量值。否则你就是在自欺欺人,浪费时间。
最重要的是,您的代码已经足够复杂,以至于您遇到了一个需要很长时间才能调试的问题。这是一种学习体验,但严格来说,你因此浪费了更多时间。在大多数情况下,您的时间成本高于运行时间。
您所需要的只是可以在两分钟内完成的微不足道的文本流 I/O。如果您不完全了解发生了什么,则不建议使用二进制存储。就目前而言,如果您尝试阅读在具有不同字节序的机器上编写的高分,您的代码将会崩溃或更糟。现在你必须管理所有数字数据的字节顺序……祝你好运。
无论如何,这实际上是一种悲观化,因为你不断地重新分配临时字符串缓冲区。不需要该缓冲区。您应该调整字符串本身的大小并将数据放入其中。
std::string name(nLen);
in.read(&name[0], name.size());
【讨论】:
是的,你是对的,“优化”绝对不是一个合适的词选择,抱歉。我相应地更改了文本。感谢您提供有关 I/O 流的提示。我会调查这个【参考方案2】:这是我正在使用的当前解决方案。这对我有用并解决了我的问题,即读取/写入 std::string 到二进制文件而不是排序方法(感谢问题中的 cmets!)。为了解决这个问题,我使用了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] = '\0';
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();
感谢大家的帮助!
【讨论】:
以上是关于C++ - 使用 std::sort 对结构向量进行排序导致读取访问冲突的主要内容,如果未能解决你的问题,请参考以下文章