std::map find doesn't work properly - c++

std::map.find() is intended to return an map::iterator to an element it found if there is some or to the end() if not. I get BadPtr returned to me. The exactly same construct works fine in the other part of code. What is this?
class OntologyContainer {
map<string, OntologyClass*> data;
OntologyClass* last_added;
public:
class iterator : public std::iterator<bidirectional_iterator_tag, OntologyClass> {
map<string, OntologyClass*>::iterator itr;
public:
iterator(map<string, OntologyClass*>::iterator it) : itr(it) { }
...
}
iterator begin() {
return iterator(data.begin());
}
iterator end() {
return iterator(data.end());
}
iterator Find(const string & to_find) {
map<string, OntologyClass*>::iterator it = data.find(to_find);
// this is where it fails
return iterator(it);
}
map::iterator is wrapped for the sake of making operators * and -> returning OntologyClass objects and pointers respectively:
OntologyClass& operator* () {
return *(itr->second);
}
OntologyClass* operator->() {
return itr->second;
}

It might be something to do with the fact that you inherit from std::iterator<bidirectional_iterator_tag, OntologyClass>, making your iterator value_type to be OntologyClass, rather than a pointer to OntologyClass, which is what your map iterator uses. How are you implementing the dereference operator?

if you can use boost I suggest using boost::transform_iterator.
This stack overflow answer has a decent example on how to do that:
iterator adapter to iterate just the values in a map?

Related

returning a iterator by reference

I want to access my iterator class by reference
#include <iostream>
template <typename T> class binary_tree;
template <typename T>
class binary_tree_iterator {
private:
binary_tree<T>* tree;
T data;
public:
binary_tree_iterator(binary_tree<T>* t) : tree(t) {}
T& operator*() {data = tree->data(); return data;}
binary_tree_iterator& operator++() {tree = tree->get_node(); return *this;}
bool operator!=(binary_tree_iterator& rhs) {return tree->data() != rhs.tree->data();}
};
template <typename T>
class binary_tree {
private:
T t_data;
binary_tree<T>* node;
binary_tree_iterator<T>* It;
public:
binary_tree(T d) : t_data(d), node(nullptr), It(nullptr)
{}
T& data() {
return t_data;
}
void set_node(binary_tree<T>* node) {
this->node = node;
}
binary_tree<T>* get_node() {
return node;
}
binary_tree_iterator<T> begin() {
It = new binary_tree_iterator<T>(this);
return *It;
}
binary_tree_iterator<T> end() {
if(node == nullptr) {
It = new binary_tree_iterator<T>(this);
return *It;
} else {
return node->end();
}
}
};
int main() {
binary_tree<int>* tree = new binary_tree<int>(2);
tree->set_node(new binary_tree<int>(3));
//for(auto& x: *tree) <--- does not work
for(auto x: *tree) {
std::cout << x << std::endl;
}
}
The for-range loop I want to use it in looks something like for(auto& x: *tree). How do I give it a reference? Is there a standard way of doing this when creating iterators? When I return the data value I assign it to a iterator data member so I can return by reference. Will I have to do the same with my iterator? I don't imagine this is the standard way of doing this.
I want to access my iterator class by reference
How do I give it a reference?
By changing the return type of the function to be binary_tree_iterator<T>& instead of binary_tree_iterator<T>. If you do that, you'd have to store an iterator somewhere instead of returning a new one, so that you can refer to it. Presumably, it would have to be stored as a member variable.
Is there a standard way of doing this when creating iterators?
No. None of the standard containers return references to iterators.
I don't imagine this is the standard way of doing this.
Indeed. The "standard" i.e. conventional thing to do is to not return references to iterators.
The for-range loop I want to use it in looks something like for(auto& x: *tree)
There is no need to return a reference to an iterator in order to make that work. If you take a look at standard containers, you'll find that none of them return a reference to an iterator, and such loop works with all of them.
The reference in that loop is bound to the result of indirection through the iterator. So, it is the operator* that must return a reference to the pointed object. And, your operator* does indeed return a reference. That said, normally an iterator would return a reference to the object stored in the container; not a reference to copy stored in the iterator. So, that's highly unconventional.
Finish writing your iterator, and you'll find that the loop works.
In conclusion: You don't need to return iterator by reference, and you shouldn't.

Valid way of accessing the address of the one-past-end element of a vector

I wanted to implement an iterator to use a custom class in a for range loop. The iterator access an internal std::vector of std::unique_ptr of a Base class and returns a raw pointer to a child class.
This is what I came up with:
using upBase = std::unique_ptr<Base>;
class Test
{
std::vector<upBase> list;
public:
void Add(upBase&& i) { list.push_back(std::move(i)); }
class iterator
{
upBase* ptr;
public:
iterator(upBase* p) : ptr(p) {}
bool operator!=(const iterator& o) { return ptr != o.ptr; }
iterator& operator++() { ++ptr; return *this; }
Child& operator*() { return *(Child*)(*ptr).get(); }
const Child& operator*() const { return *(Child*)(*ptr).get(); }
};
iterator begin() { return iterator(&list[0]); }
iterator end() { return iterator(&list[list.size()]); }
};
This works fine on the latest compilers (tested on GodBolt with GCC, Clang and MSVC) but when using Visual Studio 2015 the end() method throws a run-time exception:
Debug assertion failed. C++ vector subscript out of range.
I search the internet for a proper way to access the address of the one-past-end element of a std::vector, but didn't find anything except complicated pointer arithmetic.
I finally came up with the following implementation for the begin() and end() methods:
iterator begin() { return iterator(&list.front()); }
iterator end() { return iterator(&list.back() + 1); }
This doesn't complain at run-time. Is it the correct way to access the address of the one-past-end element of an std::array or std::vector?
If not, what would be the proper way?
What would be the proper way?
You are trying to re-invent the wheel. You do not need to implement the class iterator for your Test, as you could get the begin and end iterator from the list (i.e. std::vector<upBase>::begin and std::vector<upBase>::end)
Therefore just make them available via corresponding member functions in Test class:
class Test
{
std::vector<upBase> list;
public:
void Add(upBase&& i) { list.push_back(std::move(i)); }
auto begin() /* const noexcept */ { return list.begin(); }
auto end() /* const noexcept */ { return list.end(); }
};
(See a demo here)
Also note that the auto return is only possible since c++14. If the compiler does not support C++14, you can provide it as trailing return type, as follows (assuming at least you have access to c++11):
auto begin() -> decltype(list.begin()) { return list.begin(); }
auto end() -> decltype(list.end()) { return list.end(); }

redifining operators for iterator class c

I faced a problem of overloading the ->() operator while implementing the Iterator class. How should this operator be overloaded?
class iterator
{
private:
pair<Key_t, Val_t> p;
public:
iterator()
{
}
iterator(const iterator &i)
{
p = i.p;
}
iterator(Key_t key, Val_t v)
{
p = make_pair(key,v);
}
pair<const Key_t,Val_t>& operator *() const
{
return p;
}
iterator& operator = (const iterator &iter)
{
this->p = iter;
return *this;
}
};
tried this way unsuccessfully
&(pair<const Key_t,Val_t>&) operator ->() const
{
return &(**this);
}
This whole approach looks wrong.
An iterator isn't supposed to contain a value, it's supposed to contain at least
The information necessary to locate a value inside the container.
Information necessary to traverse to the next element within the container.
By storing a value inside the iterator, you cause unnecessary copies and lose the ability to update the container (change the value, remove the element from the container, etc).
For example, an iterator for a std::vector-like container might store a handle to the container and the index (offset) to the current item.
The only time an iterator would have a value itself is when you're implementing a generator that isn't actually associated with a container.

Unable to write my own iterator based on an STL iterator

I have a little problem while trying to implement a container, Set, based on a linked list.
Yeah, I know that there's an STL implementation of a set, but this is for homework. :)
So, this is what I have done so far:
my Set.h file looks like that:
template <class T>
class Set {
private:
typedef std::list<T> base_container;
base_container items;
public:
class myIterator {
public:
typename base_container::iterator base_iterator;
myIterator() { }
};
void addItem(const T item) {
items.push_back(item);
}
typedef typename Set<T>::myIterator setIterator;
setIterator begin() { return items.begin(); }
setIterator end() { return items.end(); }
Set<T>(void) { }
~Set<T>(void) { }
};
Now, main.cpp:
#include "Set.h"
int main(void) {
Set<int> mySet;
mySet.addItem(1);
mySet.addItem(2);
mySet.addItem(3);
mySet.addItem(4);
Set<int>::myIterator x;
x = mySet.begin(); // produces an error about non-convertible types.
return EXIT_SUCCESS;
}
The error is as follows:
error C2664: 'Set<T>::myIterator::myIterator(const Set<T>::myIterator &)' : cannot convert parameter 1 from 'std::_List_iterator<_Mylist>' to 'const Set<T>::myIterator &'
Clearly I messed things up, but I'm not sure which part of the code is actually the problem.
Any suggestions about how to fix this? Any helpful information will be appreciated.
Thanks. :)
There are many problems with your approach.
As others have said, you can't create your iterator type from the underlying type:
setIterator begin() { return items.begin(); }
setIterator end() { return items.end(); }
This can be solved by adding a constructor to your type:
class myIterator {
typedef typename base_container::iterator base_iterator_type;
public:
explicit myIterator(base_iterator_type i) : base_iterator(i) { }
base_iterator_type base_iterator;
myIterator() { }
};
This constructor should be explicit, which means you need to change how you create it:
setIterator begin() { return setIterator(items.begin()); }
The next problem is that your type doesn't implement the iterator interface, it doesn't provide operator++ or operator* etc. and it doesn't define nested types such as value_type and iteratory_category i.e. it's not an iterator (just giving it a name with "iterator" in it doesn't make it true!)
Once you fix that and your type is a valid iterator, you'll find your container can't be used with STL-style algorithms because it doesn't implement the container requirements. Among other things, it should provide a nested type called iterator not setIterator so that other template code can use S::iterator without caring if S is a std::set<T> or a Set<T>. Don't call it Set<T>::setIterator, just call it Set<T>::iterator. Also in this case there's no point defining myIterator (noone cares that it's yours! :-) then having a typedef to call it setIterator, just name the type with the right name in the first place and you don't need a typedef.
The problem is here:
setIterator begin() { return items.begin(); }
setIterator end() { return items.end(); }
The values you're trying to return have the wrong type. They are of type base_iterator and not setIterator, and there's no way to implicitly convert from the former to the latter.
You can derive from std::iterator<T> and provide the approprate iterator category tag. This will automatically give your iterator the required nested types such as value_type in terms of T. You will still need to write function members such as operator++ and operator* (depending on your iterator category, e.g. you also need operator[] for random access iterators)

How to write a c++ function what can return either iterator or reverse_iterator

As far as I can tell in c++ there is no common base class that covers both iterator and reverse_iterator.
The only suggestion I have seen so far is to get around this using templates (
How to write a function that takes an iterator or collection in a generic way? )
However this solution doesn't seem to work for me.
class MyClass
{
template<typename Iter> Iter* generate_iterator(...params...)
{
//returns either a vector::iterator or vector::reverse_iterator
}
template<typename Iter> void do_stuff(Iter *begin, Iter *end)
{
//does stuff between elements specified by begin and end
//I would like this function to remain agnostic of which direction it is working in!
}
void caller()
{
//I would like this function to remain agnostic of which direction it is working in too...
do_stuff(generate_iterator(blah),generate_iterator(foo));
}
};
In this case, generate_iterator() cannot be used as desired because the compiler complains "generate_iterator is not a member of class MyClass" presumably because I haven't specified it (which I can't in practice as caller should be agnostic of the iterator type).
Can anyone help? Thanks in advance!
edit: as Mark B pointed out generate_iterator must return a pointer - now corrected
update: just started using this http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/start_page.html and it seems to work...
You can create your own iterator class that knows how to go both directions. Encapsulate both types of iterator and internally select whichever one you were initialized with.
Here's a start:
template<typename Container>
class BiIterator
{
public:
BiIterator(Container::iterator i) : m_fwd(i), m_isforward(true) {}
BiIterator(Container::reverse_iterator i) : m_rev(i), m_isforward(false) {}
bool operator==(const BiIterator & left, const BiIterator & right);
Container::value_type & operator*()
{
if (m_isforward)
return *m_fwd;
return *m_rev;
}
const Container::value_type & operator*() const;
BiIterator & operator++()
{
if (m_isforward)
++m_fwd;
else
++m_rev;
return *this;
}
private:
Container::iterator m_fwd;
Container::reverse_iterator m_rev;
bool m_isforward;
};
In C++ you can't write a function that returns two different types. In your template case it will return one or the other depending on the instantiation. You could possibly return a base pointer to a polymorphic iterator but that would cause me to ask what you're really trying to do here. Even the standard containers don't try to do that: They have begin and rbegin to distinguish properly. I would suggest having two separate functions that each do the right thing and return one type of iterator or the other as context dictates.
As a side, note that you can't implicitly determine a template instantiation of a type that's only used for the return type of a function.
By using boost tuple and boost any , your problem can be easily solved. I wrote a example by using boost::any , see below:
#include <boost/any.hpp>
using boost::any_cast;
#define MSG(msg) cout << msg << endl;
boost::any getIterator(std::vector<int>& vec, bool bReverse)
{
if(!bReverse)
return boost::any(vec.begin());
else
return boost::any(vec.rbegin());
}
int main()
{
std::vector<int> myvec;
myvec.push_back(1);
myvec.push_back(2);
myvec.push_back(3);
typedef std::vector<int>::iterator vecIter;
typedef std::vector<int>::reverse_iterator vecRIter;
try
{
boost::any iter = getIterator(myvec, false);
boost::any iter2 = getIterator(myvec, true);
vecIter it1 = any_cast<vecIter>(iter);
vecRIter it2 = any_cast<vecRIter>(iter2);
MSG(*it1);//output 1
MSG(*it2);//output 3
return true;
}
catch(const boost::bad_any_cast &)
{
return false;
}
}
Use boost::variant or boost::any.
boost::variant< reverse_iterator, iterator >
generate_iterator(...) {
if(...) return iterator();
else return reverse_iterator();
}
// user code
boost::variant< reverse_iterator, iterator > v = generate_iterator();
if(reverse_iterator* it = boost::get<reverse_iterator>(v))
...;
else if(...)
...;
Although the variant is better accessed through a visitor.
The downside is that you need some boiler plate to extract the proper type and is exactly the reason why something like any_iterator might be a more sensible choice.