Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting vector of custom type by their constant id

I need to sort a vector of custom type std::vector<Blah> v by Blah's integer id. I do this via std::sort(v.begin(), v.end()) with the operator < being overloaded within Blah as

bool operator< (const Blah& b) const { return (id < b.id); }

I noticed that Blah's private id cannot be declared as const int id, otherwise the type Blah does not meet the requirements for std::sort (I assume it conflicts with not being ValueSwappable?)

If id is not const everything is fine. However, I dislike the idea of the objects not having constant ids just for the requirement of rearranging their order within a vector.

Is there a way around or is this the way it is?

like image 813
symphonic Avatar asked Aug 11 '15 08:08

symphonic


People also ask

How do I sort custom vectors?

You can sort a vector of custom objects using the C++ STL function std::sort. The sort function has an overloaded form that takes as arguments first, last, comparator. The first and last are iterators to first and last elements of the container.

How do you sort a vector without sorting?

The vector can use the array notation to access the elements. If you don't want to use the default std::sort , or std::sort with custom comparator, you can use qsort or write your own.

How do you sort an array of vectors?

Sorting a vector in C++ can be done by using std::sort(). It is defined in<algorithm> header. To get a stable sort std::stable_sort is used. It is exactly like sort() but maintains the relative order of equal elements.


1 Answers

Is there a way around or is this the way it is?

I fear that this is the way it is. If you want to sort a vector, which is in principle an array, then you have to assign to elements when exchanging them.

At least that is what i thought, actually you can cheat a bit. Wrap your objects into an union:

template<typename T>
union ac {
 // actual object
 T thing;
 // assignment first destructs object, then copy
 // constructs a new inplace.
 ac & operator=(ac<T> const & other) {
  thing. ~T();
  new (& thing) T(other. thing);
 }
 // need to provide constructor, destructor, etc.
 ac(T && t) : thing (std:: forward<T>(t))
 {}
 ac(ac<T> const & other) : thing (other. thing) {}
 ~ac() {
  thing. ~T();
 }
 // if you need them, add move assignment and constructor
};

You can then implement the (copy) assignment operator to first destruct the current object and then (copy) construct a new object from the provided inplace of the old object.

You also need to provide constructors and destructors, and of course this only works with C++11 and beyond due to limitations concerning the union members in previous language standards.

This seems to work quite nice: Live demo.

But still, I think you should first revisit some design choices, e.g. if the constant id really needs to be part of your objects

like image 145
Daniel Jour Avatar answered Sep 20 '22 15:09

Daniel Jour