I have a privately scoped Boost.BiMap in a class, and I would like to export a public view of part of this map. I have two questions about the following code:
class Object {
typedef bimap<
unordered_set_of<Point>,
unordered_multiset_of<Value>
> PointMap;
PointMap point_map;
public:
??? GetPoints(Value v) {
...
}
The first question is if my method of iteration to get the Point's associated with a Value is correct. Below is the code I'm using to iterate over the points. My question is if I am iterating correctly because I found that I had to include the it->first == value condition, and wasn't sure if this was required given a better interface that I may not know about.
PointMap::right_const_iterator it;
it = point_map.right.find(value);
while (it != point_map.right.end() && it->first == val) {
/* do stuff */
}
The second question is what is the best way to provide a public view of the GetPoints (the ??? return type above) without exposing the bimap iterator because it seems that the caller would have to know about point_map.right.end(). Any efficient structure such as a list of references or a set would work, but I'm a bit lost on how to create the collection.
Thanks!
The first question:
Since you are using the unordered_multiset_of collection type for the right side of your bimap type, it means that it will have an interface compatible with std::unordered_multimap. std::unordered_multimap has the member function equal_range(const Key& key) which returns a std::pair of iterators, one pointing to the first element that has the desired key and one that points to one past the end of the range of elements that have the same key. Using that you can iterate over the range with the matching key without comparing the key to the value in the iteration condition.
See http://www.boost.org/doc/libs/1_41_0/libs/bimap/doc/html/boost_bimap/the_tutorial/controlling_collection_types.html and http://en.cppreference.com/w/cpp/container/unordered_multimap/equal_range for references.
The second question:
Constructing a list or other actual container of pointers or references to the elements with the matching values and returning that is inefficient since it's always going to require O(n) space, whereas just letting the user iterate over the range in the original bimap only requires returning two iterators, which only require O(1) memory.
You can either write a member function that returns the iterators directly, e.g.
typedef PointMap::right_const_iterator match_iterator;
std::pair<match_iterator, match_iterator> GetPoints(Value v) {
return point_map.right.equal_range(v);
}
or you can write a proxy class that presents a container-like interface by having begin() and end() member functions returning those two iterators, and have your GetPoints() member function return an object of that type:
class MatchList {
typedef PointMap::right_const_iterator iterator;
std::pair<iterator, iterator> m_iters;
public:
MatchList(std::pair<iterator, iterator> const& p) : m_iters(p) {}
MatchList(MatchList const&) = delete;
MatchList(MatchList&&) = delete;
MatchList& operator=(MatchList const&) = delete;
iterator begin() { return m_iters.first; }
iterator end() { return m_iters.second; }
};
It's a good idea to make it uncopyable, unmovable and unassignable (like I've done above by deleting the relevant member functions) since the user may otherwise keep a copy of the proxy class and try to access it later when the iterators could be invalidated.
The first way means writing less code, the second means presenting a more common interface to the user (and allows for hiding more stuff in the proxy class if you need to modify the implementation later).
Related
Lets say I have an input iterator type MyInputIter (which I use to traverse a tree-like structure) that satisfies the std::input_iterator concept.
Are there any reasons why I shouldn't define begin() and end() on the iterator itself?
struct MyInputIter
{
// iterator stuff omitted
auto begin() const { return *this; }
auto end() const { return MySentinel{}; }
};
Reason being that I don't have to create another type just to wrap begin and end so I can use it in a for loop:
MyInputIter iterate(TreeNode root, FilterPattern pattern)
{
return MyInputIter{ root, pattern };
}
void foo()
{
for (auto item : iterate(someRandomTreeNode, "*/*.bla"))
process(item);
}
while also being able to use it as an iterator:
std::vector<TreeNode> vec(iterate(someRandomTreeNode, "*"), MySentinel{});
Are there any reasons why I shouldn't define begin() and end() on the iterator itself?
Potential issues to consider:
Implementing those functions for the iterator may be expensive. Either because of need to traverse the structure to find them, or because of extra state stored in the iterator.
It may be confusing since it deviates from common patterns. Edit: As pointed out by 康桓瑋, there's precedent for iterators that are ranges in std::filesystem::directory_iterator, so this may not a significant issue in general. There is another consideration whether your range implementation works in an expected way.
Reason being that I don't have to create another type
As far as I can tell, you don't need to create another type. You can use:
std::ranges::subrange(MyInputIter{ root, pattern }, MySentinel{})
In my project I have some custom classes, with roughly the structure below.
Point, which represents a 2D int coordinate
struct Point {
int x;
int y;
}
Line, which represents a line drawn between two Points
class Line {
Point start;
Point end;
}
Polygon, which represents the polygon that is defined by number of Points.
class Polygon {
private:
std::vector<Point> _vertices;
}
I'm trying to implement a custom iterator for Polygon, the goal being a syntax something like:
Polygon aPolygon;
Point somePoint;
for( auto line_it = aPolygon.begin(); line_it != aPolygon.end(); line_it++ ){
if( line_it->includes(somePoint) ){
// Do something
}
}
When iterating over Polygon the n:th element would be
Line( _vertices[n], _vertices[n+1] ),
and the last would be
Line( _vertices[_vertices.size() - 1], _vertices[0] )
How do I implement such an iterator, or otherwise acheive similar syntax with acceptable performance?
I'm looking through similar questions, but I've yet to find one similar enough for a comprehensive answer.
If possible I would prefer a STL solution that uses c++20 standard.
I realize the question was unecessarily vague, more specifically I'm asking how I can implement the *,-> and ++ operators for my iterator.
class Polygon {
public:
/* ... */
struct PolygonIterator {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = Line;
using pointer = value_type*;
using reference = value_type&;
explicit PolygonIterator( Point* ptr ) : m_ptr( ptr ) {}
reference operator*();
// ^ Should return Line reference, but I have Point in container?
PolygonIterator& operator++();
pointer operator->();
bool operator==(const PolygonIterator& other);
private:
Point* m_ptr;
};
PolygonIterator begin() { return PolygonIterator( &_vertices.front() ); }
PolygonIterator end() { return PolygonIterator( &_vertices.back() ); }
Looking at your code again, satisfying forward iterator requirements would be tricky, because you essentially generate the lines on the fly. Hence I suggest making an input iterator.
operator++ should just increment m_ptr, nothing unusual. But you might want to store an std::vector iterator instead of a pointer (then, if you enable iterator debuggning for standard containers, it will extend to your iterators).
Then you have two options:
Store the current Line inside of the iterator. Then * and -> return a reference and a pointer to it respectively. ++ will need to update this Line after incrementing the pointer/iterator.
Return the Line from operator* by value, and change using reference to Line to match the return type. This is unusal, but allowed for input iterators.
Then operator-> becomes tricky. It can't return a pointer (because there's no Line to point to), so it has to return a helper class by value, which in turn would store a Line (again by value), and overload -> to return a pointer to it. You probably should also change using pointer to match the type of this helper class.
Welcome into the world of containers which are not containers!
Since the beginning, standard library containers are expected to actually directly contain their objects. I could find 2 reference articles about that:
When Is a Container Not a Container? by Herb Sutter, and
To Be or Not to Be (an Iterator) by Eric Niebler
Long story made short your pseudo container is only a proxy container: objects exists elsewhere, and the container can only build proxies to them. It is not so uncommon and vector<bool> is such a container, and its iterators are only proxy iterators. Simply if you look into the sources of an implementation of the standard library, you will find every now and then special processing for vector<bool> in algorithm because vector<bool> iterators pretend being random access iterators when they cannot even meet the requirements of a forward container.
That means that your iterators will only be proxy iterators and their reference type will be an object (the proxy) instead of a true reference. Because of that they will be no more than simple input iterators. It is is acceptable for you, that will be enough, else you could have a look to the range library of C++20, which should start to provide some support to proxy containers and iterators.
Should I write iterators for a class that is just a wrapper of a vector?
The only private member of my class called Record is a vector.
I want to be able to do this:
for (auto& elem : record) {
// do something with elem
}
where record is of type Record. To do this I need to implement iterators
for the Record class. But, I can also do this:
for (auto& elem : record.elems) {
// do something with elem
}
where record.elems is the vector I mentioned. But this way
I will need to make it public.
Another approach is:
for (auto& elem : record.getElems()) {
// do something with elem
}
this way I get iteration, and the member stays private.
Probably this is the best way to go.
My main question is, why would I bother to implement iterators for the Record class
when it is just a wrapper for a vector? My colleague insists I implement iterators,
and he can't even explain me why, it is just stupid.
Implementing iterators will help the encapsulation of your class. If at any point in time, you decide to replace the backing vector with another data type, you might break dependencies.
Actually, you do not need to implement the iterator. You can typedef your iterators to be the vector iterators and create inline begin() and end() methods to return the vector's iterators.
EDIT: As requested a simple example:
template <class T>
class vectorWrapper
{
typedef typename std::vector<T> backingType;
backingType v;
public:
typedef typename backingType::iterator iterator;
typedef typename backingType::const_iterator const_iterator;
iterator begin() { return v.begin(); }
const_iterator begin() const { return v.begin(); }
const_iterator cbegin() const { return v.cbegin(); } // C++11
iterator end() { return v.end(); }
const_iterator end() const { return v.end(); }
const_iterator cend() const { return v.cend(); } // C++11
};
If needed (or wanted) reverse_iterators can be added the same way. Since the methods are likely to be inlined by the compiler, there is little to no overhead in using this.
If your class should look a range, you are best off to provide access to iterators via begin() and end() members. The key advantage is that objects of the class can be used consistent with other ranges: there isn't much doubt of how the class is meant to use and the effort is small: unless you don't expect your class to be used, you should make it as easy and obvious to use. Of course, if you don't expect you class to be used why bother writing it in the first place?
Whether these need to have a different type than those of the vector depends on whether you need to impose any constraints. If the class does 't impose constraints on the elements or on their order it is sufficient to pass on the iterators. Otherwise it may be necessary to create custom iterators.
For fun and profit™, I'm writing a trie class in C++ (using the C++11 standard.)
My trie<T> has an iterator, trie<T>::iterator. (They're all actually functionally const_iterators, because you cannot modify a trie's value_type.) The iterator's class declaration looks partially like this:
template<typename T>
class trie<T>::iterator : public std::iterator<std::bidirectional_iterator_tag, T> {
friend class trie<T>;
struct state {
state(const trie<T>* const node, const typename std::vector<std::pair<typename T::value_type, std::unique_ptr<trie<T>>>>::const_iterator& node_map_it ) :
node{node}, node_map_it{node_map_it} {}
// This pointer is to const data:
const trie<T>* node;
typename std::vector<std::pair<typename T::value_type, std::unique_ptr<trie<T>>>>::const_iterator node_map_it;
};
public:
typedef const T value_type;
iterator() =default;
iterator(const trie<T>* node) {
parents.emplace(node, node->children.cbegin());
// ...
}
// ...
private:
std::stack<state> parents;
// ...
};
Notice that the node pointer is declared const. This is because (in my mind) the iterator should not be modifying the node that it points to; it is just an iterator.
Now, elsewhere in my main trie<T> class, I have an erase function that has a common STL signature--it takes an iterator to data to erase (and returns an iterator to the next object).
template<typename T>
typename trie<T>::iterator trie<T>::erase(const_iterator it)
{
// ...
// Cannot modify a const object!
it.parents.top().node->is_leaf = false;
// ...
}
The compiler complains because the node pointer is read-only! The erase function definitely should modify the trie that the iterator points to, even though the iterator shouldn't.
So, I have two questions:
Should iterator's constructors be public? trie<T> has the necessary begin() and end() members, and of course trie<T>::iterator and trie<T> are mutual friends, but I don't know what the convention is. Making them private would solve a lot of the angst I'm having about removing the const "promise" from the iterator's constructor.
What are the correct const semantics/conventions regarding the iterator and its node pointer here? Nobody has ever explained this to me, and I can't find any tutorials or articles on the Web. This is probably the more important question, but it does require a good deal of planning and proper implementation. I suppose it could be circumvented by just implementing 1, but it's the principle of the thing!
1) All iterators are required to be copy-constructible. Your iterator is Bi-directional, hence is also required to be default-constructible (http://en.cppreference.com/w/cpp/concept/ForwardIterator), although I don't know why. So the default constructor needs to be public but you can do what you like with the const trie<T>* one. I would think it should be private, since the purpose of this class is to provide the user with an iterator over the trie, and so its public interface should be only that of an iterator of the appropriate category. No need for any extra public constructors.
2) erase is a non-const function. The only iterators you can validly pass to it are iterators that refer to the same trie that the function is called on, which means (I think, although I'm not quite certain I've followed your design) the whole hierarchy of parents are non-const objects. So I suspect this is one of those cases where you can const_cast<trie<T>*>(it.parents.top().node). The iterator isn't allowed to use it to modify the trie, which is why you want it to hold a pointer-to-const. But when you hold a non-const pointer to the trie, namely this, you are allowed to modify any part of it you like, and the iterator is just giving you the position to start modifying from.
There might be some more general principle of const-safety you can draw here. One possible case in container::erase(const_iterator) functions is that the const container* you'd get from the iterator is equal to this. In that case the const_cast is certainly both safe and legitimate (as well as unnecessary, because you can just use this, but that's beside the point of whether it's const-correct or not). In your container it is not (in general) equal to this, it points to one of the several trie objects that together make up the hierarchical container that this is part of. The good news is, that whole container is logically const or logically non-const together, hence the const_cast is just as safe and legitimate as if it were all one object. But a bit harder to prove correct, because you have to make sure that in your design the whole hierarchical container genuinely does, as I've assumed, share non-constness.
Non-const methods of trie that wish to modify what a const_iterator points to (what it points to should be within this instance of trie) should just const_cast as needed. You know this is a safe and defined cast because if someone managed to call a non-const instance of this trie, then this instance of trie itself is not const.*
Alternatively you could do the opposite and hold non-const pointer(s) to the trie within the const_iterator, which will require a const_cast upon construction. This is safe for the same reason, above. The const_iterator methods will only provide const access, so the user can't mutate the part(s) of trie that the iterator points to. And if a const_iterator needs to be mutated in a non-const trie method it's okay because the trie must not have been const in the first place.*
The premise of the safety of const_casting here is that it is safe to hold and use a non-const pointer to a const object so long as you do not mutate that object. And it is safe to turn a cast away the constness of a pointer which points to something which wasn't originally declared as const.
*Yes, the caller of the non-const trie method might have const_casted in an undefined way; but in that case the burdon of causing undefined behavior is on their head, not tries.
Should iterator's constructors be public?
At least the copy constructor, yes. Have a look at this chart that describes the traits each type of iterator should have:
http://www.cplusplus.com/reference/iterator/
All iterator types should be copy-constructible, copy-assignable and destructible, so that means they need public copy constructors. Some iterators, for example the RandomAccessIterator should also be default constructible so the default constructor should be public as well.
What are the correct const semantics/conventions regarding the iterator and its node pointer here?
If you want to have an erase then you don't really have a const_iterator, you have a regular iterator. The difference between the two is that if you have a const trie object then you can only get a const_iterator out of it because you're not allowed to modify it in any way.
You can notice this in the STL containers. They tend to have both:
iterator begin();
const_iterator begin() const;
What usually happens is that you implement a const_iterator then:
class iterator : public const_iterator {...};
which implements the one or two non-const functions. This probably means just erase for you, since your operator* is going to stay const.
Suppose I have a class encapsulating std container:
class Stash
{
list<int> Data;
public:
list<int>::const_iterator GetAccess() const { return Data.begin(); }
};
It's very convenient way of forcing the user to read the data in form of the iterator. However, I can't find the way other that comparing the iterator to container.end(). So, I would like to know if there's an option to do it solely by stdlib or I have to write iterator class myself (with can_advance method, for example).
Relevant question might be this one, but it asks whether the iterator is valid, not whether it can advance. I weren't able to find any information about the latter.
You can't do this, a single iterator does not contain the information when it is at the end of the sequence its pointing into.
Normally, this is solved by either providing a range (think std::make_pair(cont.begin(), cont.end())), or providing begin() and end() methods to your class, effectively making it a range.
Iterators work in pairs: an iterator that points to the beginning of a sequence and an iterator that points past the end of the sequence. That's why all the containers have begin() and end() member functions: so you can look at the sequence of values that the container manages.
It would be far more idiomatic to change the name of GetAccess to begin and to add end. Having end() would also make it possible to apply standard algorithms to the data.
What you seem to be asking for is a "lookahead" iterator. You could write a class to "adapt" an iterator to have lookahead, where the adaptor just stays one step ahead of your code:
template<class FwdIter>
class lookahead_iterator
{
public:
lookahead_iterator(const FwdIter& begin): cur_iter(begin), next_iter(++begin) {}
operator FwdIter() const { return cur_iter; }
lookahead_iterator<FwdIter>& operator ++() { cur_iter = next_iter++; return *this; }
// Other methods as needed.
private:
FwdIter cur_iter;
FwdIter next_iter;
};
Needless to say, this gets a lot more complicated if you need more than a forward iterator.