Sorting list of shared pointers - c++

Given the class
class objects {
public:
bool compareArea (const objects& obj) const { return this->area < obj.area; }
private:
double area;
};
I want to sort a
list<shared_ptr<objects>> myObjects;
I cannot use a lambda (since my toolchain's C++11 support is incomplete). Thus, I tried the following:
using namespace placeholders;
myObjects.sort(bind(&objects::compareArea,_1,_2));
This line is called from another file (not from a class member!). The problem is, that compareArea requires two objects as input. But I give two shared pointer to objects to it. Is there an easy way of how to include the dereferencing of the pointers into the sort-call? I want the objects::compareArea(..) function to stay as it is. I do not want this kind of solution
bool compareArea (const shared_ptr<objects>& ptr1, const shared_ptr<objects>& ptr2) {
return ptr1->area > ptr2->area;
}
// in same source-file:
myObjects.sort(bind(compareArea,_1,_2));
where compareArea is no member-function of objects. Actually an operator overloading of < would be my favourite solution.

I would strongly suggest that you never store any kind of pointer in a container.
Instead, make a handle class which supports the required arithmetic and comparison operators.
It makes for code that's easier to reason about:
class objects {
public:
objects(double w, double h) : area(w * h) {}
bool operator<(const objects& r) const { return this->area < r.area; }
private:
double area;
};
struct object_handle
{
object_handle(shared_ptr<objects> const& ptr) : ptr_(ptr) {}
static object_handle create(double w, double h) { return make_shared<objects>(w,h); }
bool operator < (object_handle const& r) const {
return *ptr_ < *r.ptr_;
}
shared_ptr<objects> ptr_;
};
int main() {
std::vector<object_handle> mylist;
mylist.push_back(object_handle::create(10, 7));
mylist.push_back(object_handle::create(2, 5));
std::sort(mylist.begin(), mylist.end());
}

Lambdas are just syntactic sugar for a class with operator(), so you can very easily write one directly (especially if you don't need captures):
struct Comparator
{
bool operator() (const shared_ptr<objects> &lhs, const shared_ptr<objects> &rhs) const
{
return lhs->compareArea(*rhs);
}
};
myObjects.sort(Comparator());

Related

How to properly rewrite with templates this C++ code that uses inheritance

I have a C++ code that currently looks like this: there is a class hierarchy to do perform some comparison and a list class that uses it. Which comparison operation to use is determined at runtime based on some schema object. Here is the structure:
class A{
bool doComparison(const string& s1, const string& s2) const=0;
}
class B: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
class C: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
template <class, S>
public FancyList{
shared_ptr<A> z_;
vector<S> v;
FancyList(shared_ptr<A> z) : z_(z);
void DoSmth(){
....
z_->doComparison(arg1, arg2);
}
}
typedef FancyList<string> FancyStringList;
// Determine which comparison to use at runtime
shared_ptr<A> c = nullptr;
switch(type):
case int:
c = make_shared<B>();
break;
case double:
c = make_shared<B>();
break;
FancyStringList l(c);
l.push_back("stuff");
C# used to be my main language so this code seemed ok to me. But I was told that the problem with this approach is that it uses virtual functions so there is a slight overhead in a method call. What is the proper C++-way of reorganizing this code so there is no need to have this class hierarchy and no need to use virtual functions?
Contrary to what you want, the overhead of virtual function is unavoidable because the decision of which actual function is called is made in runtime.
If the decision is always made in runtime, the compiler cannot hard-code the function call into the generated machine code. It has to be a indirect function call: to use a pointer to point to a function, and to dereference the pointer before the function call. Virtual function is just one way to do indirect function call.
Template is a way tell the compiler to generate code during compile-time. All template can do is to not introduce overhead when the decision is made during compile-time. It can't help you remove works that must be done in runtime.
If you are still interested in using template, you may consider having the comparator as a template parameter.
template <class T, class Comparator>
class MyList
{
std::vector<T> vec;
Comparator comp;
public:
void do_thing(const T& a, const T& b)
{
vec.push_back(a);
vec.push_back(b);
bool x = comp(vec[0], vec[1]); // for example
std::cout << x;
}
};
In the comparator class, overload the function call operator.
class Compare1
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs < rhs;
}
};
class Compare2
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs.size() < rhs.size();
}
};
int main()
{
MyList<std::string, Compare1> myli1;
myli1.do_thing("a", "b");
MyList<std::string, Compare2> myli2;
myli2.do_thing("c", "d");
}
You can even hide indirect function call behind comparator class. But it does not remove the overhead.
class A
{
public:
virtual bool doComparison(const std::string& s1, const std::string& s2) const=0;
virtual ~A() = default;
};
class PolymorphicComparator
{
private:
std::shared_ptr<A> comp;
public:
PolymorphicComp(std::shared_ptr<A> c) : comp(c) {}
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return comp->doComparison(lhs, rhs);
}
};

Finding a C++ object in the set by object comparision instead of using functors

I want to populate a std::set of GraphNode objects and check if another GraphNode with the same value exists in the set. In Java, objects can be compared by overloading equals and compareTo methods, instead of creating some functor object. I implemented operator==(T& t) and expected to find the object in the set like this,
std::find(nodesSet->begin(),nodesSet->end(), new GraphNode<T>(1))!=nodesSet->end())
But I am not getting the break point in neither == nor ()() operator functions. Why is it so? Is there a way to find the object by object comparison?
template<class T>
class GraphNode
{
friend class Graph<T>;
friend bool operator==(GraphNode<T>& node1, GraphNode<T>& node2);
private:
T t;
std::vector<GraphNode<T>*> adjNodes;
public:
bool operator==(T& t);
};
template<class T>
inline bool GraphNode<T>::operator==(T & t)
{
return this->t == t ? true : false;
}
template<class T>
inline bool operator==(GraphNode<T>& node1, GraphNode<T>& node2)
{
return node1.t == node2.t ? true : false;
}
void populate()
{
std::set<GraphNode<T>*>* nodesSet = new set<GraphNode<T>*>;
nodeSet->insert(new GraphNode<T>(1));
nodeSet->insert(new GraphNode<T>(2));
if ( std::find( nodesSet->begin(),nodesSet->end(),
new GraphNode<T>(1) ) != nodesSet->end() )
{
cout<<"found value";
}
}
As aschepler pointed out, the problem with your code is that you end up comparing pointers, not objects. std::find (look at the possible implementations in the linked page), if called without a predicate, uses the == operator to compare what is returned when the iterators you give it are dereferenced. In your case, you have a std::set<GraphNode<T>*> nodesSet, so the type of *nodesSet.begin() is GraphNode<T>*, not GraphNode<T> (note the lack of star). In order for you to be able to use the == operator defined for your GraphNode, you need to have your set be std::set<GraphNode<T>>, that is of objects of your type rather than of pointers.
If you have to store pointers in your set (e.g. because you don't want to copy the objects), you can write a wrapper for pointers that uses the comparison operator for the underlying class of the pointers. Here's an example:
#include <iostream>
#include <set>
#include <algorithm>
class obj {
int i;
public:
obj(int i): i(i) { }
bool operator<(const obj& o) const { return i < o.i; }
bool operator==(const obj& o) const { return i == o.i; }
int get() const { return i; }
};
template <typename T>
class ptr_cmp {
T* p;
public:
ptr_cmp(T* p): p(p) { }
template <typename U>
bool operator<(const ptr_cmp<U>& o) const { return *o.p < *p; }
template <typename U>
bool operator==(const ptr_cmp<U>& o) const { return *o.p == *p; }
T& operator*() const { return *p; }
T* operator->() const { return p; }
};
int main(int argc, char* argv[])
{
obj five(5), seven(7);
std::set<ptr_cmp<obj>> s;
s.insert(&five);
s.insert(&seven);
obj x(7);
std::cout << (*std::find(s.begin(),s.end(), ptr_cmp<obj>(&x)))->get()
<< std::endl;
return 0;
}
It turned out that my compiler (gcc 6.2.0) required both operator== and operator< for std::find to work without a predicate.
What is wrong with using a predicate though? It is a more generalizable approach. Here's an example:
#include <iostream>
#include <set>
#include <algorithm>
class obj {
int i;
public:
obj(int i): i(i) { }
bool operator==(const obj& o) const { return i == o.i; }
int get() const { return i; }
};
template <typename T>
struct ptr_cmp {
const T *l;
ptr_cmp(const T* p): l(p) { }
template <typename R>
bool operator()(const R* r) { return *l == *r; }
};
template <typename T>
ptr_cmp<T> make_ptr_cmp(const T* p) { return ptr_cmp<T>(p); }
int main(int argc, char* argv[])
{
obj five(5), seven(7);
std::set<obj*> s;
s.insert(&five);
s.insert(&seven);
obj x(7);
std::cout << (*std::find_if(s.begin(),s.end(), make_ptr_cmp(&x)))->get()
<< std::endl;
return 0;
}
Note, that make_ptr_cmp allows you to avoid explicitly stating the type, so you can write generic code.
If you can use C++11, use can just use a lambda function instead of ptr_cmp,
std::find_if(s.begin(),s.end(), [&x](const obj* p){ return *p == x; } )
std::find compares the values pointed at by the iterators. These values are pointers, not objects. So none of them will be equal to new GraphNode<T>(1), which is a brand new pointer to a brand new object.
As others have stated, you are comparing pointers, which won't work as expected, it's doing comparisons on addresses in memory. The operation a < b has a valid meaning for a pointer but will order the elements by their location in memory, not on their contained data elements and also no elements will be unique, as they will all have unique addresses. That is unless you try to insert the same element twice.
The above issue however will be hidden by using std::find, which iterates over all the elements in the container anyway. If you are using a set, you should be aspiring to get logarithmic time look ups for elements, so should use sets own find function, which knows that its a binary tree under the hood.
In C++, the equivalent of Object#equals is operator== (as you knew) and in the context of associative containers the equivalent of Object#compareTo is operator<. Object#equals and operator== work in the same way, exactly as you expect; If somethings equal its equal, simple to understand. Object#compareTo and operator< are used by algorithms in different ways, operator< is used to implement strict weak ordering to determine if one element is less than or greater than another.
So to allow your elements to be usable in a set you will need an overridden operator< in your GraphNode class. Once you have this you can use the std::set::find function to find elements in your set and it will find them in O(log n) time rather than linear time.
These algorithms are designed on the assumption they are working on value types, i.e not pointers but those things that are pointed to. So to use pointers you need to define a new comparison function that basically dereferences the pointers before applying the comparison (either == or <).
Some example code
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
template<typename>
class Graph
{
};
template<class T>
class GraphNode
{
friend class Graph<T>;
friend bool operator==(const GraphNode<T>& a, const GraphNode<T>& b);
private:
T t;
std::vector<GraphNode<T>*> adjNodes;
public:
explicit GraphNode(const T& tval)
:t(tval)
{}
T& getT(){ return t; }
const T& getT() const { return t; }
bool operator==(const T& t);
friend bool operator<(const GraphNode& a, const GraphNode& b){
return a.t < b.t;
}
};
template<class T>
inline bool GraphNode<T>::operator==(const T& t)
{
return (this->t == t);
}
template<class T>
inline bool operator==(const GraphNode<T>& a, const GraphNode<T>& b)
{
return (a.t == b.t);
}
int main()
{
using IntGraphNode = GraphNode<int>;
std::set<IntGraphNode> nodesSet;
nodesSet.insert(IntGraphNode(1));
nodesSet.insert(IntGraphNode(2));
auto findit = nodesSet.find(IntGraphNode(1));
if(findit != nodesSet.end())
{
std::cout << "found value\n";
}
auto findit2 = std::find_if(
nodesSet.begin(),
nodesSet.end(),
[](IntGraphNode i) { return i.getT() == 1;});
if(findit2 != nodesSet.end())
{
std::cout << "found value aswell\n";
}
}
The first search uses sets own find function and the second uses std::find_if, which takes a predicate (function that returns either true or false) to test equality. The second example also removes the need to make a dummy object, by exposing the T object and using that in the comparison lambda function.
Also a comment about
std::find(nodesSet->begin(),nodesSet->end(), new GraphNode<T>(1))!=nodesSet->end())
There are quite a few conceptual misunderstandings in this line. Firstly std::find does not take a comparison function, that would be std::find_if, but the compiler will tell you that (in its own especially indirect and verbose way). Also the comparison function is evaluated in the algorithm, you are trying to evaluate it at the call site. The other thing is unlike java, you can't just fire off newed objects into oblivion. That's a memory leak, you no longer have any variable storing the newed value, so you can't delete it.

Where does the operator overloading go when accessing data from a struct?

I have a function in a struct that sorts a vector in the struct. But to compare two elements in the vector, I need value of another variable inside the same struct. I was wondering where I should keep the operator overload or the compare function for this sort to work. I've given a sample in the following paste.
#include<vector>
#include<algorithm>
struct Square{
int color; //value 1 to 10
};
struct State{
vector<Square> list;
int color_weight[] = {4,3,5,2,4,1,6,4,5,9}; //These values keep changing.
bool operator<(Square& a, Square& b);
void sortTheList();
};
bool State::operator<(Square& a, Square& b){
if (color_weight[a.color]< color_weight[b.color]){
return true;
}
return false;
}
void Square::sortTheList(){
sort(list.begin(),list.end());
}
This doesn't work, of course. I've tried many other signatures and scope for the comparison function but nothing seems to work.
Any idea what can be done here?
You would use a comparator that keeps a reference to the extra state that it needs, instead of operator<. Something like this:
struct CompareWeight {
CompareWeight(int const * weight) : weight(weight) {}
bool operator()(Square const & lhs, Square const & rhs) {
return weight[lhs.color] < weight[rhs.color];
}
int const * weight;
};
void Square::sortTheList() {
std::sort(list.begin(), list.end(), CompareWeight(color_weight));
}

How can I write a comparator with a intermediate variable for stl sort

class Point
{
int x;
}
static Point referencePoint;
struct Comparator
{
bool AbsComparator(const Point& p1, const Point& p2)
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
list<Point> points;
points.sort(Comparator::AbsComparator);
But I CANNOT use a static referencePoint for multithreading safe, is there any other way??
Thanks.
Make it part of Comparator:
struct Comparator
{
Point referencePoint;
Comparator(Point referencePoint): referencePoint(referencePoint) {}
Comparator(const Comparator& rhs) {
referencePoint = rhs.referencePoint;
}
bool operator()(const Point& p1, const Point& p2) const
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
...
points.sort(Comparator(refP));
Why not simply save the referencePoint or rather the integer value inside Point as a member inside your Comparator, that way you always access it in the comparator function.
Avoid global variables. That is start of writing multi-threaded code.
Use local variables instead:
Point referencePoint(10,20); //use local variable!
points.sort(Comparator(referencePoint));
Or simpy this,
points.sort(Comparator(Point(10,20)));
where Comparator is a functor defined as:
struct Comparator
{
Point referencePoint;
explicit Comparator(const Point & pt) : referencePoint(pt) {}
bool operator() (const Point& p1, const Point& p2) const
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
You're done!
Notice the implementation of operator(). This makes the class a functor.
You can simply store this variable, either in a destructured or structured manner.
// destructured (only store what you need)
class ReferenceComparator {
public:
explicit ReferenceComparator(int x): _x(x) {}
explicit ReferenceComparator(Point const& p): _x(p.x) {}
bool operator()(Point const& left, Point const& right) const {
return abs(left.x - _x) < abs(right.x - _x);
}
private:
int _x;
}; // class ReferenceComparator
And then use it as:
list.sort(ReferenceComparator(myReferencePoint));
I would advise not using a list if you need sorting through. list are not good at it...

Declaring function objects for comparison?

I have seen other people questions but found none that applied to what I'm trying to achieve here.
I'm trying to sort Entities via my EntityManager class using std::sort and a std::vector<Entity *>
/*Entity.h*/
class Entity
{
public:
float x,y;
};
struct compareByX{
bool operator()(const GameEntity &a, const GameEntity &b)
{
return (a.x < b.x);
}
};
/*Class EntityManager that uses Entitiy*/
typedef std::vector<Entity *> ENTITY_VECTOR; //Entity reference vector
class EntityManager: public Entity
{
private:
ENTITY_VECTOR managedEntities;
public:
void sortEntitiesX();
};
void EntityManager::sortEntitiesX()
{
/*perform sorting of the entitiesList by their X value*/
compareByX comparer;
std::sort(entityList.begin(), entityList.end(), comparer);
}
I'm getting a dozen of errors like
: error: no match for call to '(compareByX) (GameEntity* const&, GameEntity* const&)'
: note: candidates are: bool compareByX::operator()(const GameEntity&, const GameEntity&)
I'm not sure but ENTITY_VECTOR is std::vector<Entity *> , and I don't know if that could be the problem when using the compareByX function object ?
I'm pretty new to C++, so any kind of help is welcome.
And a third one comes in... After you edited you question, still one open topic: your comparator takes a const & to the GameEntity class. It should, in order to work with the values of the vector<GameEntity*>, take const GameEntity* arguments instead.
A functor is a class that defines operator() so an object of that class can be "invoked" with the same syntax as calling a function:
struct functor {
bool operator()(Entity const &a, Entity const &b) {
return a.x < b.x;
}
};
If you want that as a member of your Entity class, you'd use a nested class:
class Entity {
float x;
public:
friend class byX;
class byX {
bool operator()(Entity const &a, Entity const &b) {
return a.x < b.x;
}
};
};
Then your sort would look something like this:
std::sort(ManagedEndities.begin(), ManagedEntities.end(), Entity::byX());
Alternatively, if you usually sort Entities by X, you could define operator< for Entity:
class Entity {
float x;
public:
bool operator<(Entity const &other) {
return x < other.x;
}
};
In this case, your use of sort would be a bit simpler:
std::sort(ManagedEntities.begin(), ManagedEntities.end());
Creating the comparison function as a normal member function of the Entity class, however, will lead to a sort invocation that's pretty ugly -- it'll usually need something like std::mem_fun_ref to do the job; it's sufficiently ugly that I'd generally avoid it for real code.
I did see this question, recently, though....
The answer was something in the way of: the function provided to sort should not be a member-function of something. Meaning: it should be a static function, or a free function. In case you declare it a static function, you should still precede it by Entity::compareByX in order to name it correctly.
If you define the order in the class itself, you can, as aJ already said, use a function adapter mem_fun or mem_fun_ref to pour it into a 'free' functor object.
If you want an Entity object to do the comparison, you should provide sort with an object (called a functor or comparator in this case):
struct EntityComp {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.x < b.x;
}
}
...
std::sort( v.begin(), v.end(), EntityComp() );
I believe compareByX should be a static member or lake a look here
In the light of 'what you're trying to achieve', I may do another guess... You want to be able to specify whether to compare your objects by their GameEntity::x member, or by their GameEntity::y member.
The easiest way would be to, as you did, specify a functor for each member:
struct CompareX {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.x < b.x;
}
};
struct CompareY {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.y < b.y;
}
};
CompareX compx; // create a compare object
std::sort( v.begin(), v.end(), compx );
The 'flexible' yet more cumbersome way would be to create a template functor:
#include <iostream>
using namespace std;
// a mockup of your class
struct GameEntity { float x, y, z; };
// just to be able to print it...
ostream& operator<<( ostream& o, const GameEntity& g ) {
return o << "(" << g.x << ", " << g.y << ", " << g.z << ")";
}
// cumbersome starts here...
typedef float (GameEntity::*membervar);
// a 'generic' float-member comparator
template< membervar m > struct CompareBy {
bool operator()( const GameEntity& a, const GameEntity& b ) const {
return a.*m < b.*m ;
}
};
// example code
int main() {
using namespace std;
GameEntity v[] = { {1,0,0}, {2,0,1}, {3,-1,2} };
GameEntity* vend = v + sizeof(v)/sizeof(v[0]);
sort( v, vend, CompareBy< &GameEntity::x >() );
copy( v, vend, ostream_iterator<GameEntity>( cout, "\n" ) );
}
try this..
class CompareByX
{
operator ()(const GameEntity &a, const GameEntity &b) { ... };
};
...
std::sort( this->begin(), this->end(), CompareByX);
In a nutshell, a functor is a function object - the STL looks specifically for an operator () that takes in the two parameters I've specified. If you're new to C++, I suggest you look up operators and functors - they're pretty handy even outside STL.
Edit: Jerry's answer is better, and more comprehensive.