I am currently learning STL in C++. And I was looking at references on a program I'm coding. It is using priority queue with a custom object.
struct Foo
{
std::list<int> path;
int cost;
bool operator>(const Foo& rhs) const
{
return cost > rhs.cost;
}
};
class mycomparison
{
public:
bool operator() (Foo p1, Foo p2) const{
return (p1>p2);
}
};
priority_queue<Foo,vector<Foo>,mycomparison> myPQ;
The objects in the priority queue is prioritized for ones with lower cost. I know that you are able to define custom comparators. But I'm not sure why there is an overloaded operator in the struct, and a custom one in class mycomparison, which is used in the priority queue. If I removed the overloaded operator in the struct, it refuses to run.
If someone would please explain to me the use of both code, the relations, how it affects one another, it would be much appreciated!
Thank you.
std::priority_queue uses std::less<T> as the default comparator.
If and when that is not appropriate, as in your case, you have to define a custom comparator or use another comparator that is appropriate for your need.
The implementation details of the operator() function of the comparator is entirely up to you.
Do you need the operator> function in Foo? Certainly not. You could have used:
class mycomparison
{
public:
bool operator() (Foo p1, Foo p2) const{
return (p1.cost > p2.cost);
}
};
That could have obviated the need to implement Foo::operator>.
However, using return (p1 > p2) keeps the abstractions in the right place. The details of what p1 > p2 means is best left up to Foo.
BTW, you could have used:
std::priority_queue<Foo, std::vector<Foo>, std::greater<Foo>> myPQ;
That would have made mycomparison unnecessary.
Related
In making a class, the compare method and the operator== overload should have identical functionality. Therefore, only one implementation is needed, and I'm trying to figure out if there's any reason why it should be defined in the compare method rather than the operator== overload.
Here's the structure defining comparison in compare:
class T {
// definition of field f
...
bool compare(const T& t) const {
if (this->f == t.f) { return true; }
return false;
}
friend bool operator == (const T& lhs, const T& rhs) { return lhs.compare(rhs); }
}
versus in the operator == overloading:
class T {
// definition of field f
...
bool compare(const T& t) const { return *this == t; }
friend bool operator == (const T& lhs, const T& rhs) {
if (lhs.f == t.f) { return true; }
return false;
}
}
TL;DR use second variant with 'virtual' keyword, but it will be better to get rid of this bullshit at all and use operator== only
You should use method compare() only if you have other variant of objects comparison, otherwise it does not make any sense. The reason for this is implementation of std::map, std::set, sorting alghoritms, etc., which use operator==, so if you use first variation of == implementation it will be, basicaly, your operator==, but with other name, which does not make any sense.
If you still want to do it,
-You can use first variant(where == uses compare), but make compare method virtual. In this case you will be able to overload comparison method just like in Java and it will affect on comparison, but still you can do it just by creating operator== for children class, so it still doesn't make any sense
...or you can use second one, but still using 'virtual' keyword to change implementation of parent class in children classes and if you don't like == implementation you can use compare method
Not very relatable example, but I think it might help you. In OpenCV library assignment operator= for class Mat(this class contains literally array of pixels and nothing more) don't actually copies array, but copies only a pointer on array of pixels(because it's heavy operation and it doesn't required in many cases), and for actual copying method clone() used. I think you can use the same solution for your code
at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.
I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.
Here is my general idea of my class definition:
class object {
public:
int first;
string second;
object(int f, string s) {
first = f;
second = s;
}
bool operator<(const object &comp) {
return first < comp.first;
}
};
This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.
Here is a short code extract from my main function:
includes ...
//code omitted
int main() {
multiset<object*> mmset;
mmset.insert(new object(10, "test"));
mmset.insert(new object(11, "test"));
return 0;
}
After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.
code extract from the stl:
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.
I would really appreciate it if someone could help me.
Best Greetings
Tom
You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.
It seems like you really just want a multiset<object>:
multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");
Now it will use < to compare the objects themselves.
If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:
auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);
Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.
Thank you for your help. That's seems to be a good solution to solve this problem.
I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :)
I will post it just as information for other seekers with the same problem.
You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content.
The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.
class object {
int first;
string second;
object() { };
object(int f, string s) {
first = f;
second = s;
}
bool operator()(const object *comp1, const object *comp2) const {
return comp1->first < comp2->first;
}
}
The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:
multiset(object*, object) mmset;
You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.
my problem is:
I have my program with 2 class plus the main;
I've declared a priority_queue inside a member function of a class;
I have to define the comparison and I think the code I should use is:
// Determine priority (in the priority queue)
bool operator < (const node & a, const node & b)
{
return a.getPriority() > b.getPriority();
}
Question: where Should I insert this piece of code? Could someone help me?
thanks
It looks like your operator< is possibly a poor addition to node. Ask yourself: are nodes logically comparable? Is it clear that comparing nodes (outside of the context of priorty_queue) should compare their priority? Maybe it should compare their position, or anything else they might contain. If you supply an operator< it will also make sense to have the other 5 comparison operators. If it's not clear what node < node actually compares, don't provide an operator< for nodes. In cases like this it's better to provide a custom comparer to the priority_queue...
struct NodeComparer
{
bool operator()(const node& left, const node& right)
{
return left.GetPriority() > right.GetPriority();
}
}
...
std::priority_queue<node, std::vector<node>, NodeComparer> nodeQueue;
This way your priority_queue can work as desired but you don't add illogical functionality to node.
This operator should be visible where the priority_queue is declared. As the priority queue exists only in a member I would place the operator's definition right above the given method definition in the .cpp file that implements the method.
I use data structures, and I sort these data structures a lot. These data structures are holding pointers to objects, not directly the objects themselves. Now I can write a simple comparison functor, or function, to tell the sort algorithm how to sort the pointers:
struct Object_ptr_comparer {
bool operator()(const Object* first, const Object* second) {
return *first < *second;
}
};
And use for example std::sort:
Object_ptr_comparer comp;
std::sort(data_str.begin(), data_str.end(), comp);
The only problem with this solution that I have to write extra pointer comparator functor for any type of class. Yes, I could use inheritance and polymorphism to write only the comparator of some root class, but I don't want to. Is there any other smart way to do this?
What about a template?
struct ptr_comparer {
template<typename T>
bool operator()(const T* first, const T* second) {
return *first < *second;
}
};
used like this:
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
That's what templates are for!
struct ptr_comparer {
template<class Object>
bool operator()(const Object* first, const Object* second) const {
return std::less<Object>()(*first, *second);
}
};
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
Since I've templated the operator rather than specializing the comparer directly, the compiler can deduce the types, so we don't have to put the types directly.
I use std::less rather than operator<, because it safely compares pointers to pointers (like char**), rather than relying on Undefined Behavior. std::less falls back on operator<, so it doesn't add any complexity to calling code, and there should be no downside.
I'm certain this one compiles
What is the difference between these two ways of overloading the != operator below. Which is consider better?
Class Test
{
...//
private:
int iTest
public:
BOOL operator==(const &Test test) const;
BOOL operator!=(const &Test test) const;
}
BOOL operator==(const &Test test) const
{
return (iTest == test.iTest);
}
//overload function 1
BOOL Test::operator!=(const &Test test) const
{
return !operator==(test);
}
//overload function 2
BOOL Test::operator!=(const &Test test) const
{
return (iTest != test.iTest);
}
I've just recently seen function 1's syntax for calling a sibling operator function and wonder if writing it that way provides any benefits.
Your first overload ensures that calling != on your type will always provide the opposite of calling == even if your implementation of == would change.
Your second overloaded function does not, since it is possible to provide any implementation for == and change the existing implementation in the future.
If you want to ensure that != will always be the opposite of ==, go with the first (at the cost of an extra function call which may very well become inlined anyway).
Here is a good example. Suppose that you have a class Point2D with fields x and y. If you want to implement ==, you will have to compare on field x and on field y. If you implement != by calling operator==, you have shorter code, and will have one function less to change if you ever moved to a polar representation.
Equality tests and comparisons are always susceptible to maintenance errors as the class fields change. Minimizing the number of methods that directly access state can reduce the risk of errors.
They will almost certainly compile to the same machine code.
I prefer choice 2, just because I find it awkward to say "operator==". But you could have used
return ! (*this == test)
And IMHO that's also clear and easy to understand.
I can think of many reasons (or perhaps aspects of the same reason) to write it that way. What they all boil down to is: it's DRY.
It ensures that two objects are always either == or !=
If you decide to change what's in the class, or what's used for equality testing, you only have to change it in one place
I think that conceptually, you really have two different things you're defining here:
A definition of "equality" for class Test
A useful interface by which people using this class can determine equality of their instances
With method 2, you're doing both ad-hoc. With method 1, you're defining equality in operator==, and providing the rest of the interface via operator!=.
Some languages/libraries take it even further, e.g., in Ruby you can define just <=> to compare ordered objects and mix-in Comparable and get equality, inequalities, and between?.
Version #1, while syntacticly ugly IMHO, allows you to change the equality logic in a single place (in the == operator overload). It guarantees the two overloads are always in sync.
In general, the following statement:
return !(*this == object);
allows you to define != in terms of one function. In the world of inheritance, child objects would only need to define operator== in order to use the base class operator!=:
struct Base
{
virtual bool isEqual(const Base& other) const = 0;
bool operator==(const Base& other) const
{
return isEqual(other);
}
bool operator!=(const Base& other) const
{
return !(*this == other); // Uses Base::operator==
}
};
With the above base class, defining operator!= using != would require descendants to implement more methods.
Also, !(*this == other) allows one to define a global, generic function for !=:
template <typename T>
bool operator!=(const T& a, const T& b)
{
return !(a == b);
}
Although this pattern doesn't provide much for == and !=, the differences are larger when using the relational operators: <, <=, >, >=.
In general, it is always better to implement related functionality in terms of each other. In case of operators, there are always groups. For example, != can be implemented in terms of ==; post-increment can be implemented in terms of pre-increment; >, <= and >= can be implemented in terms of < (see std::rel_ops in <utility>) etc. If something about the class needs changing, you only need to modify the core operators, and all the rest will automatically be updated to reflect the new behavior.
The general implementation of all the "secondary" operators is always the same, and so there is even a library which automatically provides operators that are defined in terms of a few provided ones. See Boost.Operators
Your example:
#include <boost/operators.hpp>
class Test : boost::equality_comparable<Test, Test>
{
private:
int iTest;
public:
bool operator==(const Test& test) const;
//look, no operator !=
};
int main()
{
Test a, b;
a != b; //still works
}