An iterator for void pointers varies quirks and oddities or how not to shoot yourself in the foot

In the old days (when C was the predominant language under the hood, and STL / templates were the dream of Alexei Stepanov), so that programmers could achieve common functions and data containers, the void* argument (for common functions) or the base container type ( for the versatility of the data container). A typical example is qsort , which is located in <cstdlib> .

Now, when dealing with legacy code bases or dinosaur-written code, it is very likely that you will come across data structures developed within this paradigm that store their elements in void** buffers. One of your main goals should be to gradually move the code base towards the use of modern STL containers and algorithms until these old data structures become obsolete. However, there are dinosaurs that you can fight with, maybe a tyrannosaurus, which happens to be your manager. To convince them of the superiority of C ++ / STL, without questioning the "usability" of legacy data structures that functioned all these years without problems and without insulting them (since they may be the original author), I decided to get involved politically.

I decided to create a template iterator that could work with such void** buffers, and will act as a bridge with STL algorithms (for example, std::sort , std::copy , etc.).

Below is one such iterator at a very early stage:

 template<typename T> class Iterator : public std::iterator<std::bidirectional_iterator_tag, T> { using T_ptr = std::remove_pointer_t<T>*; void **pos; public: Iterator(void **pos_) : pos(pos_) { } bool operator==(Iterator const &other) const { return pos == other.pos; } bool operator!=(Iterator const &other) const { return pos != other.pos; } bool operator<( Iterator const &other) const { return pos < other.pos; } bool operator>( Iterator const &other) const { return pos > other.pos; } bool operator<=(Iterator const &other) const { return pos <= other.pos; } bool operator>=(Iterator const &other) const { return pos >= other.pos; } Iterator& operator++() { ++pos; return *this; } Iterator operator++(int) { Iterator out(*this); ++pos; return out; } Iterator& operator--() { --pos; return *this; } Iterator operator--(int) { Iterator out(*this); --pos; return out; } Iterator& operator+=(int const n) { pos += n; return *this; } Iterator& operator-=(int const n) { pos -= n; return *this; } T& operator[](int const n) { *static_cast<T_ptr>(*(pos + n)); } T& operator*() { return *static_cast<T_ptr>(*pos); } T_ptr operator->() { return static_cast<T_ptr>(*pos); } friend Iterator operator+(Iterator const &lhs, int const n) { Iterator out(lhs); out.pos += n; return out; } friend Iterator operator-(Iterator const &lhs, int const n) { Iterator out(lhs); out.pos -= n; return out; } friend Iterator operator+(int const n, Iterator const &rhs) { Iterator out(rhs); out.pos += n; return out; } friend Iterator& operator-(int const n, Iterator const &rhs) { Iterator out(rhs); out.pos -= n; return out; } friend int operator-(Iterator const &A, Iterator const &B) { return B.pos - A.pos; } }; 

My goal is to use this iterator as follows. Suppose I had the following class:

 struct Foo { int val = 0; explicit Foo(int val_) : val(val_) {} Foo() = default; Foo(Foo const&) = default; Foo(Foo &&) = default; Foo& operator=(Foo const&) = default; Foo& operator=(Foo &&) = default; bool operator< (Foo const& rhs) const { return val < rhs.val; } bool operator==(Foo const& rhs) const { return val == rhs.val; } }; 

And the following buffer is void* :

 Foo f1(1), f2(2), f3(3), f4(4); void* v[] = {&f4, &f2, &f1, &f3}; 

I want to use std::sort to sort v with respect to the Foo objects it contains:

 std::sort(Iterator<Foo>(v), Iterator<Foo>(v + sizeof(v) / sizeof(void*))); 

Live demo

I tried to inherit my iterator from std::iterator< std::bidirectional_iterator_tag , T> , rather than std::iterator< std::random_access_iterator_tag , T> , to avoid treating the void** buffer as a continuous buffer of T so that it can to have consequences.

Q

Is this iterator circuit safe? Are there any quirks or oddities that I should be aware of?

+5
source share

Source: https://habr.com/ru/post/1258425/


All Articles