2

I am looking for a type of container in which pointers to objects do not change on item addition/removal (even from the middle). Order of items with the same priority can change.

It can be a part of Boost. Ideas?

Why?

So I can keep objects in one place (one container) and still have them sorted. There is a need to pass pointers to other objects.

In case of std::set

Is it safe to store pointers of MyType to elements of such a set? The elements are going to be modified by member functions of each, but properties used for comparison will remain intact through lifetime of each object in a set.

Update: in case someone decided to stick with C++ STD or head toward Boost; it is worth to look at this: Boost MultiIndex

underscore_d
  • 5,331
  • 3
  • 29
  • 56
Vega4
  • 591
  • 8
  • 21
  • 1
    Please can you clarify your meaning of 'stable'? In the context of sorted containers, normally this means that the order of equal items does not change upon sorting. – Paul Floyd Jun 23 '17 at 10:22
  • I've updated my question. There was already explanation that I mean the requirement for the behaviour of pointers to objects to be defined (ie.stable) on item addition/removal. That is not the case for std::vector for example. – Vega4 Jun 23 '17 at 10:24

2 Answers2

7

Take a look at std::set (or std::multiset, if stored elements might be the same).

First of all, they are sorted.

Then, on addition/removal operations all references and iterators (if they do not point to the removed element in case of removal) remain unaffected.

For more information about containers and references/iterators invalidation check this thread.

Edgar Rokjān
  • 16,412
  • 4
  • 37
  • 63
  • please take a look at an updated version of my question (related to the safety of pointers to modifiable objects) and I shall accept. I would create another question but the very problem is heavily related to the 'stability' of a data structure. – Vega4 Jun 23 '17 at 13:05
  • @Rafal as you are not changing data that is used for sorting you should be fine with `std::set`. Otherwise you can use `boost.multiindex` and sort it anyway you want. – Slava Jun 23 '17 at 13:10
  • @Slava I guess, OP won't be fine as `std::set` returns only const iterators, so only const methods are available... – Edgar Rokjān Jun 23 '17 at 13:12
  • @EdgarRokyan if objects are stored by pointer then they would be fine, but if stored by value yes that would require `const_cast`, so `boost.multiindex` could be more applicable. – Slava Jun 23 '17 at 13:14
  • @Slava that's exactly what I mean. – Edgar Rokjān Jun 23 '17 at 13:15
  • after reading what you say; I'm considering two options 1) storing objects by value in a vector and having pointers to them sorted by means of std::set OR 2) using boost.multiindex ; seems like if I got with 1) I would have to take care of managing two different data structures at the same time (deletion etc.) – Vega4 Jun 23 '17 at 13:18
  • @Rafal right, and that exact reason why `boost.multiindex` exists - you do not need to maintain mutiple containers with the same data manually. – Slava Jun 23 '17 at 13:22
  • @Rafal I'm not well familiar with boost, but maintaining two data structures instead of one seems to be a bad idea... – Edgar Rokjān Jun 23 '17 at 13:30
0

A simple way to keep pointers to objects valid even when iterators get invalidated is to use a container of smart pointers.

To keep sorted containers sorted when inserting, one can use this insertion technique:

std::vector<unique_ptr<Object>> v;
unique_ptr<Object> po;

// this will insert new item as the first item of same-value objects within the container
v.insert(std::lower_bound(v.begin(), v.end(), po, [](auto& x, auto& y) { *x.get() < *y.get(); }), po);

// this will insert new item as the last item of same-value objects within the container
v.insert(std::upper_bound(v.begin(), v.end(), po, [](auto& x, auto& y) { *x.get() < *y.get(); }), po);
Michaël Roy
  • 5,382
  • 1
  • 12
  • 17