comparision function in stl::sort() - c++

class node{
public:
unsigned long long int value;
int index;
};
bool comp2(node& a,node& b){
if(a.value < b.value) { return true; }
return false;
}
vector <node*>llist,rlist;
sort(llist.begin(),llist.end(),comp2);
Above code was giving me some weired error that is too in some other lines(places latter in code), but when i changed comp2 function to following all error disappeared .
bool comp2(node* a,node* b){
assert(a && b && "comp2 - null argument");
if(a->value < b->value){ return true; }
return false;
}
Any rationale on this ?
ERROR:/usr/include/c++/4.4/bits/stl_algo.h|124|error: invalid initialization of reference of type ‘node&’ from expression of type ‘node* const’|
If this(bellow) works then above should also work
using namespace std;
void rep(int& a,int& b){
int c;
c=a;
a=b;
b=c;
}
int main(void){
int a=3,b=4;
rep(a,b);
cout<<a<<" "<<b;
return 0;
}

You have defined a std::vector of node *. Therefore, all the elements are node *, and all operations that the vector performs will be on node *. You can't give sort a comparison function of a different type.

The rational is that your vector contains values of type node*, so the comparison functions needs to compare values of type node*.

What you probably meant to say in the first place was vector<node>. If you wanted pointers to nodes, then the second comparison function is reasonable.

Related

C++ sort algorithm segmentation fault [duplicate]

Can someone explain why the sort below causes seg faults? Is this a known bug with g++ (sorting vector of pointers)? I am compiling with g++ 4.5.2.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<int> A;
bool face_cmp(const A *x, const A *y) {
return x != y;
}
int main(int argc, char* argv[]) {
vector<A *> vec;
for (int i=0; i<100; i++) {
vec.push_back( new vector<int>(i%100, i*i) );
}
vector<A *>::iterator it;
sort(vec.begin(), vec.end(), face_cmp);
return EXIT_SUCCESS;
}
Compiling on codepad gives:
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/debug/safe_iterator.h:240:
error: attempt to decrement a dereferenceable (start-of-sequence)
iterator.
Objects involved in the operation:
iterator "this" # 0x0xbf4b0844 {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPPN15__gnu_debug_def6vectorIiSaIiEEEN10__gnu_norm6vectorIS7_SaIS7_EEEEENS4_IS7_SB_EEEE (mutable iterator);
state = dereferenceable (start-of-sequence);
references sequence with type `N15__gnu_debug_def6vectorIPNS0_IiSaIiEEESaIS3_EEE' # 0x0xbf4b0844
}
Thank you for the all the quick replies. The original comp function was:
if (x == y) return false;
if (x->size() < y->size()) return true;
else if (x->size() > y->size()) return false;
else {
for (register int i=0; i<x->size(); i++) {
if ((*x)[i] < (*y)[i]) return true;
}
return false;
}
I just changed the first line and removed the rest. But it turns out it also suffers from not being a strict weak ordering (I forgot the case if (*x)[i] > (*y)[i]). I should probably have posted the entire function to begin with. Nevertheless, thanks again!!
The comparison function must define a strict weak ordering which means that a < b and b < a cannot be both true. Your comparison function does not have this property.
It does not define any "before-after" relationship, so it's no wonder that the algorithm relying on this property does not function properly.
Third argument of std::sort should be a function (or functional object) such that if compare(a, b) is true then compare(b, a) should be false, but your one isn't such. So your program is UB and can give any result.
No your code is wrong. Comparison functions for std::sort must use < or it's equivalent, using != is not correct. Probably you want this
bool face_cmp(const A *x, const A *y) {
return *x < *y;
}
Ensure that you're just using greater than or less than. DO NO USE equal to. Equal to will SEGFAULT with certain data sets:
// Good
bool face_cmp(const A *x, const A *y) {
return *x < *y;
}
// Also okay for reverse sorting
bool face_cmp(const A *x, const A *y) {
return *x > *y;
}
// This will SEGFAULT
bool face_cmp(const A *x, const A *y) {
return *x <= *y;
}
The real danger with <= is the lack of repeatability. I had some C++ code that SEGFAULT'ed on Android, while happily running on my x86 PC. For me, the magic number was 68 elements, 67 was fine, 68 SEGFAULT'ed.
Define your comparison function as
bool face_cmp(const A *x, const A *y) {
return x < y;
}

Can the qsort() function be used with a function template as the comparator?

I am trying to create a function template that receives an array as input and sorts it. In order to sort it, I thought I could use the qsort() function that is included in the header file cstdlib of the C++ standard library. The qsort() function requires a comparator function to be passed as an argument, which in this case needs to be a function template as well.
Unfortunately I simply cannot get it to work. The program compiles successfully if the comparator function is not a function template, but if it is, I get an error that says
no matches converting function ‘compare2’ to type ‘__compar_fn_t {aka int (*)(const void*, const void*)}’
To give you an idea of what I am talking about, here is an example:
#include <cstdlib>
using namespace std;
int compare2(const void *pa, const void *pb)
{
int a = *(const int*) pa;
int b = *(const int*) pb;
if (a > b) {
return -1;
} else if (a < b) {
return 1;
} else {
return 0;
}
}
template <typename type>
void mySort(type* ptr, unsigned int n) //n represents size of array pointed to by ptr
{
qsort(ptr, n, sizeof(ptr[0]), compare2);
return;
}
The above code compiles without any problems, despite the fact that it wouldn't work in practice if an array containing anything other than integers was passed to the mySort() function.
Whereas the following code:
#include <cstdlib>
using namespace std;
template <typename type>
int compare2(const void *pa, const void *pb)
{
type a = *(const type*) pa;
type b = *(const type*) pb;
if (a > b) {
return -1;
} else if (a < b) {
return 1;
} else {
return 0;
}
}
template <typename type>
void mySort(type* ptr, unsigned int n) //n represents size of array pointed to by ptr
{
qsort(ptr, n, sizeof(ptr[0]), compare2);
return;
}
fails to compile with the error that I previously mentioned.
I know that I can easily achieve my goal using other methods (such as using a sorting algorithm inside the mySort() function in the given example), however I really want to get to the bottom of this. Why does qsort() not work with a function template as comparator? Is it due to a mistake I've made or is it simply not possible?
compare2 is a template, not a function. To get a function, a compiler has to instantiate a template. To do that, it should know the template parameters. Typically, they can be deduced from function parameters. In the present case, no deduction is possible, so you have to be explicit by adding <type> to the template name:
qsort(ptr, n, sizeof(ptr[0]), compare2<type>);

C++ check if value was assigned to member of class

I have a uni assignment in which I have to create a custom template which acts as an array of doubles. It also has to implement a sorting algorithm which sorts the elements in descending order. I designed the template so it has an internal array of doubles with the length declared by the user (MyArray<10> contains a double array with a length of 10). My custom array will only be filled up with doubles in ascending order from myArr[0] and values won't be changed once assigned, but they can be any value so I can't have a magic constant to keep track of them. Instead I have to check the number of assignments to the array so when I call the sort() method, it knows which is the last changed element.
My subscript operator:
Proxy &operator[](int elem) {
if(elem > arr_size - 1) {
throw std::out_of_range("Out of range");
}
std::cout << "a" << std::endl;
return Proxy(*this, elem);
}
And the proxy class which is inside the F8 class:
class Proxy {
private:
F8 &a;
int id;
public:
Proxy(F8 &a, int id) { this.a = a; this.id = id; };
int& operator=(int x) { curr_num++; return a.arr[id]; }
};
Is there a way to check if operator[] is in an assignment (or if it is an lvalue)? I have tried it with a proxy class but it just seems too complicated for a beginner C++ class and that way I have to implement all of the operators (the values get compared etc, so when with operator[] I return a double it can be compared directly, but when I return the Proxy class, the compiler gives an error for every operator because they don't exist, and the task doesn't ask me to implement all the operators needed for comparison).
Thank you for your time!
Edit: I get the following error when I try to return a proxy class in which I can keep track of the assignment operator:
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'F8<433>::Proxy')
Also to make things clear: the array will be filled in the ascending order of indexes, so after I assign a value to myArr[0] comes myArr[1].
I seems to me like you are looking for a user defined conversion.
class Proxy {
private:
F8 &a;
int id;
public:
Proxy(F8 &a, int id) { this.a = a; this.id = id; };
int& operator=(int x) { curr_num++; return a.arr[id]; }
operator int() const { return a.arr[id]; }
// ^ int or double? You say double but your example code seems to be using int.
};
Not sure how/what your assignment operator is supposed to do. Right now it's only returning a value from your array but not actually assigning anything.
What about something like
int& operator=(int x) { curr_num++; a.arr[id]=x; return a.arr[id]; }

Debugging a C++ code

I am not able to understand what is being returned from function in following code (pointer or value) .
#include<iostream>
using namespace std;
class safearay
{
int a[10];
public:
int& operator [](int n)
{
if(n<0 || n>5 )
{
cout<<"Exceeded bounds"<<endl;
}
return a[n];
}
};
int main()
{
safearay sa1;
for (int j=0;j<10;j++)
{
sa1[j]=j*j;
}
for (int j=0;j<10;j++)
{
int u=sa1[j];
cout<<u<<endl;
}
}
Please explain
int& operator [](int n)
returns a reference to an int.
Essentially, you can use it as int, but changes will affect a[n] in the class too (because it's returned). It's like a pointer without all the *, except you can't change the address where it points to.
Pay attention that in your code you do this:
safearay sa1;
sa1[j]=j*j;
Normally you cannot access the object values like this. The method you're asking about is the operator overload method, that defines what whould the object do on such an access.
int& operator [](int n)
{
if(n<0 || n>5 )
{
cout<<"Exceeded bounds"<<endl<<;
}
return a[n];
}
means
return the reference to the value in the n'th place of the array a in object safearay if n is in
range
The return value is passed by reference, therefore you can assign to it and the change will be in a[i]
You can read more about operator overload here
More about passing values by reference here

Why does std::sort throw a segmentation fault on this code?

Can someone explain why the sort below causes seg faults? Is this a known bug with g++ (sorting vector of pointers)? I am compiling with g++ 4.5.2.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<int> A;
bool face_cmp(const A *x, const A *y) {
return x != y;
}
int main(int argc, char* argv[]) {
vector<A *> vec;
for (int i=0; i<100; i++) {
vec.push_back( new vector<int>(i%100, i*i) );
}
vector<A *>::iterator it;
sort(vec.begin(), vec.end(), face_cmp);
return EXIT_SUCCESS;
}
Compiling on codepad gives:
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/debug/safe_iterator.h:240:
error: attempt to decrement a dereferenceable (start-of-sequence)
iterator.
Objects involved in the operation:
iterator "this" # 0x0xbf4b0844 {
type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPPN15__gnu_debug_def6vectorIiSaIiEEEN10__gnu_norm6vectorIS7_SaIS7_EEEEENS4_IS7_SB_EEEE (mutable iterator);
state = dereferenceable (start-of-sequence);
references sequence with type `N15__gnu_debug_def6vectorIPNS0_IiSaIiEEESaIS3_EEE' # 0x0xbf4b0844
}
Thank you for the all the quick replies. The original comp function was:
if (x == y) return false;
if (x->size() < y->size()) return true;
else if (x->size() > y->size()) return false;
else {
for (register int i=0; i<x->size(); i++) {
if ((*x)[i] < (*y)[i]) return true;
}
return false;
}
I just changed the first line and removed the rest. But it turns out it also suffers from not being a strict weak ordering (I forgot the case if (*x)[i] > (*y)[i]). I should probably have posted the entire function to begin with. Nevertheless, thanks again!!
The comparison function must define a strict weak ordering which means that a < b and b < a cannot be both true. Your comparison function does not have this property.
It does not define any "before-after" relationship, so it's no wonder that the algorithm relying on this property does not function properly.
Third argument of std::sort should be a function (or functional object) such that if compare(a, b) is true then compare(b, a) should be false, but your one isn't such. So your program is UB and can give any result.
No your code is wrong. Comparison functions for std::sort must use < or it's equivalent, using != is not correct. Probably you want this
bool face_cmp(const A *x, const A *y) {
return *x < *y;
}
Ensure that you're just using greater than or less than. DO NO USE equal to. Equal to will SEGFAULT with certain data sets:
// Good
bool face_cmp(const A *x, const A *y) {
return *x < *y;
}
// Also okay for reverse sorting
bool face_cmp(const A *x, const A *y) {
return *x > *y;
}
// This will SEGFAULT
bool face_cmp(const A *x, const A *y) {
return *x <= *y;
}
The real danger with <= is the lack of repeatability. I had some C++ code that SEGFAULT'ed on Android, while happily running on my x86 PC. For me, the magic number was 68 elements, 67 was fine, 68 SEGFAULT'ed.
Define your comparison function as
bool face_cmp(const A *x, const A *y) {
return x < y;
}