Sorting a Vector of a custom class with std::sort() causes a segmentation fault - c++

I'd like to sort a vector of a custom class using std::sort() and overloading the < operator. Following the answer here: Sorting a vector of custom objects, I tried the following code:
class Evnt {
private:
int Day, Month;
string mydata;
public:
friend ifstream& operator >>(ifstream &in,Evnt &E){
char junk;
in >>junk>>E.Month>>junk>>E.Day;
getline(in,E.mydata);
return in;
}
bool operator<(const Evnt &E) const{
if(Month < E.Month)
return true;
else if(Day < E.Day)
return true;
return false;
}
};
int main(){
ifstream inpt("inputfile.txt")
Vector <Evnt> v;
Evnt tmpevnt;
while(intp>>tmpevnt)
v.push_back(tmpevent)
sort(v.begin(), v.end());
return 0;
}
The last line somewhat erratically causes segmentation faults. I followed the various examples fairly closely, and so am having issues figuring out what the problem is. It seems to only occur if I read a large number (~20+) items in.

std::sort requires a comparison operation that imposes Strict Weak Ordering.
That means that if a < b returns true, b < a must not return true.
Fix your comparison operator.
bool operator<(const Evnt &E) const{
if(Month < E.Month)
return true;
else if(Month == E.Month && Day < E.Day)
return true;
return false;
}
See this similar question for more information.

Related

How to overload == operator to see if two objects with a string vector are equal?

I am writing a class named StringSet which has vector<string> data and int length as its private members.
bool StringSet::operator == (StringSet d)
{
for (int i = 0; i < length; i++)
{
if (data[i] == d.data[i])
{
return true;
}
}
return false;
}
When I try calling this function like this,
StringSet doc1, doc2;
if (doc1 == doc2)
{
cout << "Both sentences are identical!\n";
}
I get an assertion failure saying vector subscript out of range, I know what that means but I don't know how it implies here. If anyone can point out an obvious mistake I have made that would be great as I am a newbie to c++.
It's simple
bool StringSet::operator == (const StringSet& d) const
{
return data == d.data;
}
std::vector and std::string have already comparison operators, therefore you don't have to implement something special.

std::sort vector of struct invalid operator<

I have problem with strict weak ordering in the compare function in std::sort. I can't see why this would fail.
I have some nested structs:
struct date{
int day = 1;
int month = 1;
int year = 2017;
};
struct hhmmss{
int hours = 1;
int minutes = 1;
int seconds = 1;
};
struct dateAndTime {
date d;
hhmmss t;
};
struct Trade
{
/*
other unrelevant data
*/
dateAndTime timeClosed;
};
In my code, at some point I have a populated std::vector<Trade> which I want to sort.
My sort function:
void sortTradesByDate(std::vector<Trade>& trades){
std::sort(trades.begin(), trades.end(), compareDateAndTime);
}
My comparison function:
bool compareDateAndTime(const Trade& t1, const Trade& t2){
if (t1.timeClosed.d.year < t2.timeClosed.d.year)
return true;
else if (t1.timeClosed.d.month < t2.timeClosed.d.month)
return true;
else if (t1.timeClosed.d.day < t2.timeClosed.d.day)
return true;
else if (t1.timeClosed.t.hours < t2.timeClosed.t.hours)
return true;
else if (t1.timeClosed.t.minutes < t2.timeClosed.t.minutes)
return true;
else if (t1.timeClosed.t.seconds < t2.timeClosed.t.seconds)
return true;
return false;
}
When running the function, and debuging, my first item passed to compareDateAndTime() passes after returning true on one of the statements (months).
The next item returns true at hours comparison, but then I get a "Debug Assertion Failed!" with "Expression: invalid operator<".
Doing some googling, this has to do with strict weak ordering. But why does this fail when comparing int variables?
Your comparison function isn't implementing strict weak ordering
Consider this scenario:
t1: year=2017, month=2
t2: year=2016, month=5
compareDateAndTime(t1, t2) would return true.
You should proceed to compare month if and only if year is the same.
if (t1.timeClosed.d.year < t2.timeClosed.d.year)
return true;
if (t1.timeClosed.d.year > t2.timeClosed.d.year)
return false;
if (t1.timeClosed.d.month < t2.timeClosed.d.month)
return true;
if (t1.timeClosed.d.month > t2.timeClosed.d.month)
return false;
... and so forth ...
A nice way to leverage the Standard Library:
return std::tie(t1.timeClosed.d.year, t1.timeClosed.d.month) < std::tie(t2.timeClosed.d.year, t2.timeClosed.d.month);
You can add the missing members inside the std::tie's (it's a variadic template). This uses std::tuple's operator<, which is defined to do what you expect.

Using find in map with user defined class as key

I have define a class Entry with 2 integer values a and b, and a vector of Entry 'e'. Now, I am going to define a map' m' of Entry and int where int is number of time that entry appear in vector. The thing is find function is considering Entry(1,2),Entry(1,12) and Entry(1,13) as one. Two entries should be same when both a and b are equal. But here if only a is equal its considering the two entries as same.
#include<iostream>
#include<map>
#include<vector>
using namespace std;
class Entry{
public:
int a;
int b;
Entry(int,int);
bool operator <(Entry);
bool operator >(Entry);
bool operator ==(Entry);
};
Entry::Entry(int x,int y):a(x),b(y){
}
bool Entry::operator ==(Entry e){
if(a==e.a && b==e.b)
return true;
else
return false;
}
bool Entry:: operator <(Entry e){
if(a<e.a)
return 1;
else
return 0;
}
bool Entry:: operator >(Entry e){
if(a>e.a)
return 1;
else
return 0;
}
int main(){
map<Entry,int> m;
vector<Entry> e;
e.push_back(Entry(1,2));
e.push_back(Entry(10,21));
e.push_back(Entry(1,13));
e.push_back(Entry(1,2));
e.push_back(Entry(1,12));
for(int i=0;i<e.size();i++){
if(m.find(e[i])==m.end())
m[e[i]]=1;
else{
m[e[i]]=m[e[i]]+1;cout<<e[i].a<<" "<<e[i].b<<" "<<m[e[i]]<<endl;
}
}
}
std::map is using the relational operator < for ordering and checking key uniqueness. Since your implementations of operator< use the a member only for comparing it will ignore b when evaluating key equality. operator== is not used from the map interface - it is replaced by !(a < b || b < a). You need something like
bool Entry::operator<(const Entry& e){
return a < e.a || a == e.a && b < e.b;
}
You could remove operator> and operator== or keep them if you need them for other purposes.

Segmentation Fault while comparing strings

In my program, there is a part where i need to sort an array of struct.
Everything goes nice until the end i think.
For some entries everything is nice and works until some entries at the end of the array.
There it throws a segmentation fault and i don't know why.
struct overview_table{
string o_timestamp;
string n_timestamp;
string dbID;
};
sort(overview.begin(),overview.end(),compareStrings);
static bool compareStrings(const overview_table &a_timestamp, const overview_table &b_timestamp){
cout << "744" << endl;
if ( a_timestamp.n_timestamp.compare(b_timestamp.n_timestamp) <= 0){
cout << "746" << endl;
return true;
} else {
cout << "749" << endl;
return false;
}
}
For information: the output was only to check where the segmentation fault is thrown. And it is between 744 and 746 and how i think at the end of the array. But i don't know why
If i'm not wrong, to sort 2 structs you have to compare the whole struct, not only a field. And you're comparing only the n_timestamp field. Second, you don't put <= in the comparison but just < or >.
This is an example of an operator overload:
bool operator<(const overview_table &a, const overview_table &b)
{
if ( a.n_timestamp.compare(b.n_timestamp) < 0) {return true;}
if ( a.n_timestamp.compare(b.n_timestamp) > 0) {return false;}
if ( a.o_timestamp.compare(b.o_timestamp) < 0) {return true;}
if ( a.o_timestamp.compare(b.o_timestamp) > 0) {return false;}
return a.dbID.compare(b.dbID);
}
hope this helps. Pleas ask if I was not clear!
The compare function shall satisfy the principle of weak ordering.
Change the function the following way
static bool compareStrings( const overview_table &a_timestamp,
const overview_table &b_timestamp )
{
return a_timestamp.n_timestamp < b_timestamp.n_timestamp;
}
A little more source would be nice...
But first of all: compare should return 0 in case of equality, so your
if ( a_timestamp.n_timestamp.compare(b_timestamp.n_timestamp) <= 0)
doesn't make any sense... Otherwise (if it's intended) your function's name is misleading.
To figure out, where your segmentation fault comes from, we need to see more sourcecode, but Segmentation faults indicate, that you are trying to acces nestet values from a null pointer, so in your case it seems, that one of your compared structs was never created...
Which could and should be checked by a if (null == x) return false; or something like that

Error in function sort

I'm trying to use the sort function from STL, but it gives me an error during execution.
My compare function returns true if v is smaller then e:
bool smallerThan(VertexEntry &v, VertexEntry &e) {
if(v.v[0] < e.v[0]) return true;
else if(v.v[1] < e.v[1]) return true;
else if(v.v[2] < e.v[2]) return true;
return false;
}
and here is the call:
sort(vertices.begin(),vertices.end(),smallerThan);
The size of the vector is aprox 400 elements.
Can somebody help me solve my problem?
Thank you!!
Your comparison function is incorrect - it doesn't enforce strict weak ordering.
Use this:
bool smallerThan(VertexEntry const & v, VertexEntry const & e) {
if (v.v[0] < e.v[0])
return true;
else if(v.v[0] > e.v[0])
return false;
else if(v.v[1] < e.v[1])
return true;
else if(v.v[1] > e.v[1])
return false;
else if(v.v[2] < e.v[2])
return true;
return false;
}
Your comparison operator doesn't enforce strict weak ordering. If you're able to use boost one trick I've seen is to bind your object to a boost::tuple and use its strict weak operator<.
If you need to write it yourself, something like this should work:
bool smallerThan(const VertexEntry &v, const VertexEntry &e)
{
if(v.v[0] != e.v[0]) return v.v[0] < e.v[0];
else if(v.v[1] != e.v[1]) return v.v[1] != e.v[1];
else return v.v[2] < e.v[2];
}