我尝试相对简单的任务 - 创建一个矢量并对其进行排序。但遗憾的是,当从堆栈中销毁向量时,它会因SIGTRAP而失败。当我删除排序时,它可以,但我宁愿需要它。
我已将问题缩小到最小的源代码。当我运行它时,我得到Windows错误“程序意外停止”。当我使用附加的GDB时,它会在完成第一个while循环后突出显示向量析构函数。 (见下图)
我尝试了vector<Vec> veci(n);
和resize(n)
。我觉得它可能是由排序算法以某种方式排序向量中不存在的项目引起的,但代码并没有表明问题......你看到了吗?
Windows 10,mingw gcc
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ctime>
#include <stack>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
#include <sstream>
using namespace std;
struct Vec {
int cena;
int vaha;
float pomer;
bool operator < (const Vec& oth) const
{
return !(pomer < oth.pomer);
}
};
int main(int argc, char** argv) {
stringstream file;
file << "9550 40 600 14 223 38 230 3 54 1 214 13 118 4 147 15 16 2 104 5 56 49 154 40 106 24 234 18 34 33 195 7 74 10 129 12 159 42 37 41 10 11 185 6 243 45 87 32 57 20 87 9 26 16 201 39 0 23 128 39 194 21 10 46 1 8 28 30 59 26 130 35 160 22 91 34 180 19 16 31 1 17 72";
while (file.good()) {
int id;
int n;
int M;
file >> id;
file >> n;
file >> M;
vector<Vec> veci;
veci.resize(n);
for (int i = 0; i < n; i++) {
int c, v;
file >> v;
file >> c;
veci[i].vaha = v;
veci[i].cena = c;
veci[i].pomer = c / (v+1);
}
sort(veci.begin(), veci.end());
}
printf("end");
return 0;
}
答案 0 :(得分:2)
您的问题源于使用while (file.good())
,这实际上总是一个错误(在这种情况下)。
这并没有检测到文件的结尾是正确的,并且最后将最后一项写入向量两次 - 但是你只为它写了一次空间,所以这写了过去分配空间的结束。
当排序尝试使用现在已损坏的堆上的数据时,您会开始看到问题。
更正非常简单:正确读取数据,例如:
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ctime>
#include <stack>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;
struct Vec {
int cena;
int vaha;
float pomer;
bool operator < (const Vec& oth) const {
return !(pomer < oth.pomer);
}
friend std::istream &operator>>(std::istream &is, Vec &v) {
return is >> v.vaha >> v.cena >> v.pomer;
}
friend std::ostream &operator<<(std::ostream &os, Vec const &v) {
return os << "{" << v.vaha << ", " << v.cena << ", " << v.pomer << "}";
}
};
int main(int argc, char** argv) {
stringstream file;
file << "9550 40 600 14 223 38 230 3 54 1 214 13 118 4 147 15 16 2 104 5 56 49 154 40 106 24 234 18 34 33 195 7 74 10 129 12 159 42 37 41 10 11 185 6 243 45 87 32 57 20 87 9 26 16 201 39 0 23 128 39 194 21 10 46 1 8 28 30 59 26 130 35 160 22 91 34 180 19 16 31 1 17 72";
std::vector<Vec> veci { std::istream_iterator<Vec>(file), std::istream_iterator<Vec>{ } };
sort(veci.begin(), veci.end());
std::copy(veci.begin(), veci.end(), std::ostream_iterator<Vec>(std::cout, "\n"));
return 0;
}
最后一点说明:您的比较功能与大多数人的期望相反。如果您在结构的pomer
字段中输入NaN,那么它也将失败(完全)(NaN不遵循严格的弱排序,如{的比较运算符所要求的那样{1}})。
答案 1 :(得分:2)
导致SIGTRAP的直接问题是你的比较运算符:
bool operator < (const Vec& oth) const
{
return !(pomer < oth.pomer);
}
它实现为“! <
”,即>=
,因此返回true
表示相等的元素。如果operator<
要使用true
,std::sort
必须永远不会返回return power > oth.pomer
。要求总结为here。
您可以改为file.good()
。
请注意,int
在您的情况下正常工作,因为在解析最后的72值后,没有空格,eof
的提取将由resize
终止,从而影响流状态。但是,它很脆弱,因为流的状态在任何时候都很好,你可以假设未来的流媒体操作有效。在信任您尝试流入的变量之前,最好先测试一下流状态仍然不错,特别是如果您正在执行类似#define ASSERT(X, MSG) \
do { \
if (!(X)) { \
std::cerr << "ASSERT fail @" << __LINE__ \
<< " !(" #X ") " << MSG << "\n"; \
exit(EXIT_FAILURE); \
} \
} while (false)
while (file >> skipws && file.good())
{
int id;
int n;
int M;
ASSERT(file >> id >> n >> M, "unable to read 'id n m' fields");
vector<Vec> veci;
veci.resize(n);
for (int i = 0; i < n; i++) {
int c, v;
ASSERT(file >> v >> c,
"unable to read 'c v' fields for [" << i << ']');
ASSERT(v + 1 != 0, "'v' value would trigger divide by zero");
veci[i].vaha = v;
veci[i].cena = c;
veci[i].pomer = c / (v+1);
}
}
之后的数组索引。
更强大的I / O示例:
select
array(select distinct unnest(colors) from item) all_colors,
array(select distinct unnest(sizes) from item) all_sizes,
min(price) min_price,
max(price) max_price
from item;
all_colors | all_sizes | min_price | max_price
-------------------------------+--------------+-----------+-----------
{yellow,blue,white,green,red} | {xl,s,l,xxl} | 100 | 300
(1 row)
答案 2 :(得分:0)
好的,问题是veci[i].pomer = c / (v+1);
分配给两个int
的浮点变量divison,因此解决方法是使用pomer = float(c) / (v+1)
。
不过,我认为原始代码应该排序不正确。我不明白为什么它完全失败,特别是在矢量的desctrutor上......任何人?
//编辑:我不知道为什么它现在有效。但问题可能在于@Jerry Coffin的回答。我稍后会做出反应。