0

This is a simplified version of the problem I have been banging my head against.

I have an abstract base class, "Widget", which has two properties, "type" and "name". Derived from this I have a "NullWidget" of which there will only ever be one, it is a placeholder for a "None" entry in a list. I also have "SmallWidget" and "LargeWidget" child classes.

I want to have a collection of these child classes, all of which will be unique by type and name, and I want to be able to present them to a user in a list sorted by type then name. I have implemented a std::less function to do this and I want to use a std::set which will enforce both ordering and uniqueness.

I also want to have a variable to reference the currently selected item in the set.

The problems I am having are manifold. Initially I had problems because I could NOT get a non-const reference/index/pointer to the selected item. The iterator type of std::set is stated as being a const iterator to a non-const value type, but when I dereference the iterator and use it as non-const the compiler complains. I have not had this problem with other container classes.

I solved that with a very nasty inline function to use a C style cast to cast the address of the object pointed to by the iterator to a non-const pointer. This is not a satisfactory solution. In fact I hesitate to even use the word "solution" in conjunction with this particular piece of code.

I am now getting issues regarding the fact that this is an abstract base class. Maybe I should have used a pointer to the abstract base class? But then I have issues with cleanup and the syntax of my std::less comparison function.

I am currently considering writing my own container class, specific to "Widget" using a std::vector of pointers or something and my own sort algorithm, but its a lot of work and I feel like I am re-inventing the wheel.

Any nice neat STL solutions will be gratefully received.

AlastairG
  • 4,119
  • 5
  • 26
  • 41
  • 1
    I suggest having a `std::vector>` as you collection and then when you add elements into it do a binary search to find the correct inert location to maintain the order. You could even not sort the vector to begin with and only sort it when presenting to the user. This also gives you the ability to only call sort when needed which should increase performance. – NathanOliver Sep 13 '22 at 15:34
  • 3
    `std::set` actually [requires its elements to be const](https://stackoverflow.com/questions/38768432/why-does-stdset-seem-to-force-the-use-of-a-const-iterator/38768680) because otherwise you could change an element and invalidate the order the set imposes. Maybe none of your non-`const` accesses ever change the traits that `std::set` uses to perform its ordering. Nathan's suggestion to use `std::vector>` is very reasonable. – Nathan Pierson Sep 13 '22 at 15:40
  • 2
    It should be possible to assemble a set of unique_ptrs in a set, using a custom comparator. One needs to fully understand the fact that sets is an ordered container, and the relative ordering, as defined by the set's comparator, is immutable, and avoid triggering undefined behavior. – Sam Varshavchik Sep 13 '22 at 15:52
  • @Nathan Pierson, I thought that might be the reason. In fact the ordering elements are constant so I thought I could get away with it, but apparently not. I'll try the other Nathan's suggestion. It would be good if he could put it as a an actual answer so I can accept it. – AlastairG Sep 15 '22 at 06:41

0 Answers0