This question already has answers here:
Reference invalidation after applying reverse_iterator on a custom made iterator
(2 answers)
Closed 5 years ago.
I created a pseudo-container class (it does not contain any elements) and an iterator class for this container.
The following code always outputs '776' on my system (my compiler is GCC 5.4.0)
#include <iostream>
#include <iterator>
class Container
{
public:
class Iterator;
Container()=default;
Container::Iterator begin();
Container::Iterator end();
};
class Container::Iterator: public std::iterator<std::bidirectional_iterator_tag, size_t>
{
public:
Iterator(size_t n);
size_t& operator*();
Container::Iterator& operator--();
const Container::Iterator operator--(int);
bool operator==(const Container::Iterator& rhs) const;
bool operator!=(const Container::Iterator& rhs) const;
private:
size_t n_;
};
Container::Iterator Container::end()
{
return Iterator(777);
}
Container::Iterator::Iterator(size_t n):
n_(n)
{
}
size_t& Container::Iterator::operator *()
{
return n_;
}
Container::Iterator& Container::Iterator::operator--()
{
n_--;
return *this;
}
const Container::Iterator Container::Iterator::operator--(int)
{
Container::Iterator oldVal = *this;
n_--;
return oldVal;
}
int main()
{
Container cont;
std::reverse_iterator<Container::Iterator>revit(cont.end());
//as cppreference says, "For a reverse iterator r constructed from an iterator i, the relationship &*r == &*(i-1) is always true...", so I expect that the output must be the same as if I used instead next commented line, and it does so on my system
// auto it = cont.end(); it--; std::cout << *it << std::endl;
std::cout << *revit << std::endl;
return 0;
}
But when I use any online compiler (with C++11 support), this code outputs just '0' (except one Clang version, then the output is some 'random' big number)
I can't figure out, where is my error?
std::reverse_iterator::operator* is equivalent to
Iterator tmp = current; return *--tmp;
(where current is the underlying iterator wrapped by this instance of reverse_iterator).
*tmp returns a reference to the member of tmp - which goes out of scope and is destroyed when std::reverse_iterator::operator* returns, taking that member with it. Therefore, *revit returns a dangling reference; the subsequent attempt to use it exhibits undefined behavior.
Related
the code below is an adoption from here and implements a user-defined random access iterator for a class holding a dynamic array in a shared pointer. In member function any the std::any_if, which requires an input_iterator, is called. From my knowledge and comments here using a random_access_iterator instead of an input_iterator should be perfectly legal. Unfortunately it does not compile with g++ and clang++ with the error message:
In file included from iterator.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/iostream:39:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/ostream:38:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/ios:40:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/char_traits.h:39:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../include/c++/11.1.0/bits/stl_algobase.h:2065:25: error: invalid operands to binary expression ('xx<long long>::Iterator' and 'xx<long long>::Iterator')
__trip_count = (__last - __first) >> 2;
It compiles when the iterator category is changed to input_iterator.
Any ideas about the root of the problem are highly appreciated.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <memory>
using namespace std;
template <typename T>
class xx{
struct Iterator
{
using iterator_category = std::random_access_iterator_tag;
//using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
Iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
Iterator& operator++() { m_ptr++; return *this; }
Iterator operator++(int) { Iterator tmp = *this; ++(*this); return tmp; }
friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; };
friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
protected:
std::shared_ptr<T[]> m_data;
int n=0;
public:
xx()=default;
xx(int n):n{n}{m_data=shared_ptr<T[]>(new T[n]);};
~xx(){};
Iterator begin() { return Iterator(&m_data.get()[0]); }
Iterator end() { return Iterator(&m_data.get()[n]); }
const int sz()const{return(n);}
void any(xx<long long int> &id){
if(any_of(id.begin(),id.end(),[this](long long int i){return(i<0 || i>(this->sz()-1));})){
std::string msg="error";throw msg;
}
}
};
int main(){
xx<double> x(10);int i=0;
xx<long long int> y(5);
cout<<x.sz()<<endl;
for(auto s=x.begin();s!=x.end();++s){
*s=(double)i++;
}
i=0;
for(auto s=y.begin();s!=y.end();++s){
*s=i++;
}
for(auto i : x){
cout<<i<<endl;
}
x.any(y);
return(0);
}
A random access iterator is one that (a) has the random access iterator tag, and (b) fullfills the requirements of being a random access iterator.
Yours fails on (b).
You need to implement [] - and + and related and < etc. And obey the other rules and requirements with them.
The tag determines which implementation your iterator is dispatched to; yours fails to provide expected features for the iterator category you claim to have, so it breaks.
The standard states that lying about your iterator category means passing your iterator in makes your program ill formed, no diagnostic required. In this case, an optimized implementation that works faster on random access iterators exists, but breaks on your lie.
In the codebase I inherited, there is a class that look like an iterator (this isn’t the exact code, but the logic is similar).
template <class T>
struct IteratorLike {
T* next() &; // either return a pointer to a valid value or nullptr
};
The way you use it is very similar to the way you use Rust iterators:
IteratorLike<...> it = ...;
while(auto* item = it.next()) {
do_something(*item);
}
How do I convert it to make it compatible with C++ range-based for loop, algorithms, or range-v3? I’m using C++14 (gcc5.5 to be more precise), so I can’t have a sentinel type that is different from the type of the iterator itself.
So far it seems that the easiest way is to store both the iterator and the next value in my wrapper:
template <class T>
class MyIterator {
private:
IteratorLike<T> m_iter;
T* m_value;
public:
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
using iterator_category = std::input_iterator_tag;
reference operator*() const {
assert(m_value && "trying to read past the end of the iterator");
return *m_value;
}
pointer operator->() {
// I’m not sure the assert is needed here
assert(m_value && "trying to read past the end of the iterator");
return m_value;
}
// Prefix increment
MyIterator& operator++() {
m_value = m_iter.next();
return *this;
}
// Postfix increment
MyIterator operator++(int) {
MyIterator tmp = *this;
++(*this);
return tmp;
}
// used by `my_collection.begin()`
explicit MyIterator(IteratorLike<T> iter)
: m_iter{m_iter}
, m_value{this->self.next()}
{}
// missing operator == and operator != as well as the constructor
// used `my_collection.end()
};
However, I fail to understand what my_collection.end() should return (EDIT: I just check, I can’t default-initialize m_iter), nor how to have meaningful comparison operators.
Note: I’m basically trying to do the exact reverse of this.
Since IteratorLike isn't default constructible, but is obviously copy constructible, you could use the instance you have to construct your end() iterator too. Example:
// used by `my_collection.begin()`
explicit MyIterator(const IteratorLike<T>& iter) :
m_iter{iter},
m_value{m_iter.next()}
{}
// used by `my_collection.end()`
MyIterator(const IteratorLike<T>& iter, std::nullptr_t) :
m_iter{iter},
m_value{nullptr}
{}
bool operator!=(const MyIterator& rhs) const {
return m_value != rhs.m_value;
}
Then in my_collection:
template<typename T>
class my_collection {
public:
MyIterator<T> begin() { return MyIterator<T>{itlike}; }
MyIterator<T> end() { return {itlike, nullptr}; }
private:
IteratorLike<T> itlike;
};
So I need to make try/catch for when the iterator is at the front of the list and the -- operator is used. I've tried checking to see if the iterator is equal to begin() but that doesn't seem to work.
template <typename E>
class List : public SLinkedList<E> {
public:
// NOTE THE DIFFERENT LETTER – IT IS ONLY USED HERE!
// Use E everywhere else! m
// For a nested class, methods are declared and defined *INSIDE*
// the class declaration.
template <typename I>
class Iterator {
public:
// Give List access to Iterator private fields.
friend class List<E>;
// These are the minimum methods needed.
E operator*() { return nodePosition->elem; } //dereference the iterator and return a value
Iterator<E> operator++() {
try {
if (nodePosition->next == nullptr)
throw OutsideList("\nIterator:Error: attempted acess position outside of list.");
nodePosition = nodePosition->next;
}
catch (OutsideList err) {
cout << err.getError() << endl;
}
return *this;
} //increment the iterator
Iterator<E> operator--() {
try {
if (nodePosition == llist.begin())
throw OutsideList("\nIterator:Error: attempted acess position outside of list.");
nodePosition = nodePosition->prev;
}
catch (OutsideList err) {
cout << err.getError() << endl;
}
return *this;
} //decrement the iterator
bool operator==(const Iterator<E> p) {
return (nodePosition == p)
} //test equality of iterators
bool operator!=(const Iterator<E> p) {
return (nodePosition != p.nodePosition);
} //test inequality of iterators
private:
// Constructors & destructor here since only want List class to access.
// List constructor called from List::begin(). Use initializer list or
// create class copy constructor and assignment overload.
Iterator(const List<E>* sl) : llist(sl) {
nodePosition = sl->head;
}
// Class fields.
const List<E>* llist; //give Iterator class a handle to the list
Node<E>* nodePosition; //abstracted position is a pointer to a node
}; /** end Iterator class **/
/* The Iterator class is now fully defined. The rest of these
statements must go AFTER the Iterator class or the compiler
won’t have complete information about their data types.
*/
// REQUIRED: While not necessary for the code to work, my test suite needs
// this defined. Create a less cumbersome name for Iterator<E>. Use
// anywhere you would have used List<E>::Iterator<E> in class List. Allows
// this syntax in main() -- List<int>::iterator instead of List<int>::Iterator<int>.
typedef typename List<E>::Iterator<E> iterator;
/*** All method declarations and fields for the List class go here.
Any method that returns an iterator must be defined here.
***/
iterator begin() const { //return an iterator of beginning of list
// Call iterator constructor with pointer to List that begin() was
// called with.
return iterator(this);
}
E back();
E pop_back();
void push_back(const E e);
iterator end() const {
iterator itr = iterator(this);
while (itr.nodePosition->next != nullptr) {
++itr;
}
++itr;
return itr;
}
void insert(int itr, E elem);
void erase(int itr);
};
bool operator==(const Iterator<E> p) {
return (nodePosition == p);
}
does not seem right. The main problem is that you are comparing nodePosition of the current object, the object on the LHS, with the object on the RHS.
You don't need Iterator<E>. Just Iterator is good enough.
There is no point in making the argument const Iterator. It can be just Iterator, or better const Iterator&.
Make the member function a const member function.
The comparison needs to be made with the corresponding nodePositions.
Here's what I think it should be:
bool operator==(const Iterator& p) const {
return (nodePosition == p.nodePosition);
}
This question already has answers here:
How to use two functions, one returning iterator, the other returning const_iterator
(2 answers)
Closed 9 years ago.
I read some other threads related to this issue but non offered a solution for my problem. I hope you guys can give me ideas or advices.
I'm trying to implement this class named Map. it should contain 2 iterators - iterator and const_iterator.
I have them implemented - iterator inherits from const_iterator, and in the Map class I have the following functions:
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
we were given an example file to see what is required to implement.
in there, there is the following code:
Map<std::string,int> msi;
...
// print map
for(Map<std::string,int>::const_iterator it = msi.begin(); it != msi.end(); ++it) {
// more stuff here
}
since msi is a non-const Map instance, msi.begin() calls to iterator begin() and not const_iterator begin() const, resulting in unintended behaviour.
Assuming the example file is okay, how do I make it so msi.begin() calls the correct const_iterator function? (considering it, the iterator, is of type const_iterator).
EDIT: regarding the talk about the auto-conversion, i decided to add my iterator classes, please point out my mistake.
class Map {
//...
public:
class const_iterator {
private:
Node* currNode;
public:
const_iterator(Node* cur_node = NULL) : currNode(cur_node) {}
const_iterator& operator++() {
currNode = currNode->next;
return *this;
}
const_iterator operator++(int) {
const_iterator old = *this;
++(*this);
return old;
}
bool operator!=(const_iterator const& curr) {
return !(*this == curr);
}
string operator*() {
// this might cause memory leak
string toString(this->currNode->key);
std::stringstream s;
int tmp = this->currNode->value;
s << tmp;
string secondString(s.str());
toString = toString + ":" + secondString;
return toString;
}
bool operator==(const_iterator const& curr) {
return this->currNode == curr.currNode;
}
void operator=(const_iterator target) {
this = target;
}
//void operator=(Node* target) {
// this->currNode = target;
//}
};
class iterator : public const_iterator {
private:
Node* currNode;
public:
iterator(Node* cur_node = NULL) : currNode(cur_node) {}
iterator& operator++() {
currNode = currNode->next;
return *this;
}
iterator operator++(int) {
iterator old = *this;
++(*this);
return old;
}
bool operator==(iterator const& curr) {
return *this == curr;
}
bool operator!=(iterator const& curr) {
return !(*this == curr);
}
string operator*() {
// this might cause memory leak
string toString(this->currNode->key);
std::stringstream s;
int tmp = this->currNode->value;
s << tmp;
string secondString(s.str());
toString = toString + ":" + secondString;
return toString;
}
void operator=(iterator target) {
this = target;
}
};
//..
}
C++11 standard containers add cbegin and cend for that purpose. Lacking that, you can obviously always cast your object to const& explicitly to get a const view on the object.
More fundamentally, however, there’s no reason why your iterator shouldn’t support an automatic conversion to const_iterator. Like that, you’d not need to change the client code at all. In fact, your code should already support this if, as you’ve said, iterator inherits from const_iterator.
However, the code you’ve posted contains several errors. Firstly, operator= is wrong, and you should have received an error for it. The corrected version is:
void operator=(const_iterator target) {
currNode = target.currNode;
}
More importantly, your inheritance makes no sense. True, you do inherit iterator from const_iterator but your code pretends that this never happened – iterator completely reimplements its parent class and doesn’t relate to it in any way.
iterator should rather look something like this:
class iterator : public const_iterator {
public:
iterator(Node* cur_node = NULL) : const_iterator(cur_node) {}
};
This requires of course that currNode is declared protected in const_iterator. That class is also completely useless (but so is yours, at the moment) since it doesn’t add any functionality to the const_iterator class. You need to implement an operator* which allows modifying its value. Your current code fundamentally doesn’t allow this since it returns a newly created string rather than (something akin to) a reference to a map value.
Furthermore, it’s unclear how the const_iterator class gets ahold of a non-const Node pointer in the first place. That shouldn’t be possible: after all, it gets the pointer from a const Map.
If you will define msi
const Map<std::string,int> msi;
instead of
Map<std::string,int> msi;
const version of begin() and end() will be invoked
I would like to define the subsequent code in order to be able to use it like
"for (auto x:c0){ printf("%i ",x); }"
But I do not understand something and i have searched it for some time.
The error I get is:
error: invalid type argument of unary ‘*’ (have ‘CC::iterator {aka int}’)
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int iterator;
public: iterator begin(){return (iterator)0;}
public: iterator end(){return (iterator)0x20;}
public: int& operator*(iterator i){return this->a[(int)i];}
} ;
int main(int argc, char **argv)
{ class CC c0;
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}
It seems you are trying to use int as you iterator type using the member operator*() as the deference operations. That won't work:
The operator*() you defined is a binary operator (multiplication) rather than a unary dereference operation.
You can't overload operators for built-in types and an iterator type needs to have a dereference operator.
To be able to use the range-based for you'll need to create a forward iterator type which needs a couple of operations:
Life-time management, i.e., copy constructor, copy assignment, and destruction (typically the generated ones are sufficient).
Positioning, i.e., operator++() and operator++(int).
Value access, i.e., operator*() and potentially operator->().
Validity check, i.e., operator==() and operator!=().
Something like this should be sufficient:
class custom_iterator {
int* array;
int index;
public:
typedef int value_type;
typedef std::size_t size_type;
custom_iterator(int* array, int index): array(array), index(index) {}
int& operator*() { return this->array[this->index]; }
int const& operator*() const { return this->array[this->index]; }
custom_iterator& operator++() {
++this->index;
return *this;
}
custom_iterator operator++(int) {
custom_iterator rc(*this);
this->operator++();
return rc;
}
bool operator== (custom_iterator const& other) const {
return this->index = other.index;
}
bool operator!= (custom_iteartor const& other) const {
return !(*this == other);
}
};
You begin() and end() methods would then return a suitably constructed version of this iterator. You may want to hook the iterator up with suitable std::iterator_traits<...> but I don't think these are required for use with range-based for.
Dietmar Kühl explained well why your code does not work: you cannot make int behaving as an iterator.
For the given case, a suitable iterator can be defined as a pointer to int. The following code is tested at ideone:
#include <stdio.h>
class CC{
int a[0x20];
public: typedef int* iterator;
public: iterator begin() {return a;}
public: iterator end() {return a+0x20;}
} ;
int main(int argc, char **argv)
{
class CC c0;
int i = 0;
for (auto& x:c0){
x = ++i;
}
for (auto x:c0){
printf("%i ",x);
}
printf("\n");
return 0;
}