"lvalue required as increment operand" about C++ & stl vector's begin() - c++

I'm trying to implement a vector(just like the one in STL).
Here is part of my code
template <class T, class alloc>
class vector
{
public:
typedef T value_type;
typedef const value_type * const_iterator;
typedef value_type * iterator;
iterator start;
iterator finish;
iterator end_of_storage;
iterator begin() {return start;}
iterator end() {return finish;}
...
}
And when I'm trying compile codes below
vector<char> characters(2, 2);
cout << *++(characters.begin()) << endl;
Here comes the error
error: lvalue required as increment operand
I'm not sure what happened, I think characters.begin() should be a lvalue. I've looked at the one in SGI STL and I couldn't find anything.
Many thanks for any advice.

This issue arises because you are using raw pointers as iterators. When you return a raw pointer (or other primitive type, such as int) from function it is not a modifiable value. However it can be easily fixed by using class iterator:
template<typename T>
struct base_iterator
{
T * m_p_value;
base_iterator &
operator ++(void)
{
++m_p_value;
return *this;
}
T &
operator *(void)
{
return *m_p_value;
}
};
// inside of vector
typedef base_iterator< value_type > iterator;
online compiler

Related

How to implement standard iterators in class

I have classes which are usually using standard containers as underlying fields. For example, I have a class
template <typename T>
class Vec_3D
{
public:
/* ... */
std::array<T, 3> vec;
/* ... */
};
which has only one variable vec and the rest are just functions I need when working with vectors. I want to be able to use range-based for loop such as
Vec_3D<double> vec;
for (double val : vec) {/*...*/}
which should obviusly iterate over std::array<double, 3>.
How to implement iterators in my class which should in turn call iterators of std::array<T, 3>?
I started with this question and tried to define iterators in my class as
typedef std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, T*, T&> iterator;
typedef std::iterator<std::random_access_iterator_tag, const T, ptrdiff_t, const T*, const T&> const_iterator;
inline iterator begin() noexcept { return vec.begin(); }
inline const_iterator cbegin() const noexcept { return vec.cbegin(); }
inline iterator end() noexcept { return vec.end(); }
inline const_iterator cend() const noexcept { return vec.end(); }
but got compiling errors
error: no match for ‘operator!=’ (operand types are ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’ and ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’)
and operator++, operator*
std::iterator is (was) a helper type to define the typedefs that a typical iterator requires. These typedefs within the class in turn make std::iterator_traits work with your iterator.
It does not, however, actually implement the required operations for you.
It was deprecated, because the std committee didn't like specifying that standard iterators had to have those typedefs, and writing the typedefs was not much bulkier than figuring out what arguments to pass to the std::iterator template.
The easy thing to do here is to just steal your underlying container's iterator. This makes your abstraction leak, but it is efficient and easy.
template <typename T>
struct Vec_3D {
using container=std::array<T, 3>;
using iterator=typename container::iterator;
using const_iterator=typename container::const_iterator;
iterator begin() { return vec.begin(); }
iterator end() { return vec.end(); }
const_iterator begin() const { return vec.begin(); }
const_iterator end() const { return vec.end(); }
private:
/* ... */
container vec;
/* ... */
};
If you don't want to expose your underlying container type, if you are willing to guarantee your underlying container is a contiguous buffer you can do:
template <typename T>
struct Vec_3D {
using iterator=T*;
using const_iterator=T const*;
iterator begin() { return vec.data(); }
iterator end() { return vec.data()+vec.size(); }
const_iterator begin() const { return vec.data(); }
const_iterator end() const { return vec.data()+vec.size(); }
private:
/* ... */
std::array<T,3> vec;
/* ... */
};
as pointers are valid iterators.
If you find you are writing this "I am a modified container" boilerplate too much, you can automate it:
template<class Container>
struct container_wrapper {
using container=Container;
using iterator=typename container::iterator;
using const_iterator=typename container::const_iterator;
iterator begin() { return m_data.begin(); }
iterator end() { return m_data.end(); }
const_iterator begin() const { return m_data.begin(); }
const_iterator end() const { return m_data.end(); }
protected:
Container m_data;
};
and then
template <typename T>
class Vec_3D:private container_wrapper<std::array<T,3>> {
// ...
};
but even that might be a bit much, why not just:
template <typename T>
class Vec_3D:public std::array<T,3> {
// ...
};
It is true that deleting Vec_3D through a pointer to base is undefined behavior, but who deletes pointers to standard containers?
If this worries you:
template <typename T>
class Vec_3D: private std::array<T,3> {
using container = std::array<T,3>;
using container::begin();
using container::end();
// ...
};
lets you inherit privately, then bring certain operations back into scope.
A range-based for loop only requires that your class have begin() and end() methods (or overloads of std::begin() and std::end()) that return iterators. It doesn't care where those iterators come from. So, the simplest solution is to just use the array's own iterators instead of trying to define your own, eg:
template <typename T>
class Vec_3D
{
public:
typedef typename std::array<T, 3> array_type;
typedef typename array_type::iterator iterator;
typedef typename array_type::const_iterator const_iterator;
// or:
// using array_type = std::array<T, 3>;
// using iterator = array_type::iterator;
// using const_iterator = array_type::const_iterator;
...
inline iterator begin() noexcept { return vec.begin(); }
inline const_iterator cbegin() const noexcept { return vec.cbegin(); }
inline iterator end() noexcept { return vec.end(); }
inline const_iterator cend() const noexcept { return vec.cend(); }
...
private:
array_type vec;
};
std::iterator is a base class only, its basically a container for some traits, but if you wanted to use it to implement your own iterator class you'd need to derive from it.
However you don't need to use it, there was a proposal to deprecate it, you could just define those traits directly in an iterator that you write. The following question has info on the proposal and help with implementing an iterator class:-
Preparation for std::iterator Being Deprecated
At the moment you're defining your container's iterator types using that base, not a class that can actually do any iterating, which is why it fails.
You expose the array as a public member. If you're happy to expose that your vec_3d is implemented using an array (whether you continue to expose the member array publicly or not) then you could just use the array's iterators - its not clear from the question that your iterator needs any bespoke behaviour just because your container adds some functionality.

how to define and access custom iterator

I am trying to make a custom iterator and I am struggling with syntax part of how to define/declare and eventually access it. Below is my attempt, which results in below error:
Error C2440 'initializing': cannot convert from 'int' to 'int *'
If someone can point me to right way to define/declare it - it would be great, for I believe my access method is standard.
Declaration
template <typename T>
class ddeque
{
public:
typedef T* iterator;
T& begin();
T& end();
}
Definition
template<typename T>
T& ddeque<T>::begin()
{
iterator = &(this->unified_array());
return iterator;
}
template<typename T>
T& ddeque<T>::end()
{
iterator = &(this->unified_array + this->size());
return iterator;
}
Access part --
In test.cpp file
// Comparing values from custom template with standard template
typename ddeque<T>::iterator itt = a.begin();
typename deque<T>::iterator ittg = g.begin();
while ((itt != a.end()) && (ittg != g.end()))
{
if (display)
{
cout << *itt << " ";
}
++itt;
++ittg;
}
P.S : I have just kept relevant part of iterator - please let me know if additional code snippet is required.
As pointed by SO member АндрейБеньковский I was returning reference instead of pointer- correct solution for definition would be ( what got it working )
Declaration:
template <typename T>
class ddeque
{
public:
typedef T* iterator;
iterator begin();
iterator end();
}
Definition
template
T* ddeque::begin()
{
iterator = &(this->unified_array());
return iterator;
}
template<typename T>
T* ddeque<T>::end()
{
iterator = &(this->unified_array + this->size());
return iterator;
}
In general:
how to define and access custom iterator
You should make a contaner class and an iterator class. The latter should be derived from std::iterator<>. You have to specify iterator tag, return value, ect. Depending on the iterator tag, you should be implementing the operators (increment, decrement, ect.). (Or better, implement everything you can which has a maximum of logarithmic complexity, then set best iterator tag.)
So begin, and end should be returning your iterator. Take a look at some stl container implementations, they are not so hard to read.
In your code
ou have made a typdef T* iterator;. This line makes another name for the pointer to T type. For readability, and to make it easier to change later, you should be returning iterator with begin and end, so:
iterator begin();
iterator end();
In the definition of the above functions, you cannot assign a value to the iterator type, I suggest returning the pointer (or iterator), for example in end():
return this->unified_array + this->size();
I think unified_array is a pointer, so I used it that way.

Questions about an array template in C++

I'm taking a course where we're being introduced to a few software patterns, one of them being the iterator pattern, and we're being asked to implement it in C++. Our professor gave us some sample code a few weeks ago and I'd like to understand it a little better than I do. First I'll post the code:
template <class T_,std::size_t SIZE_>
class carray {
public:
typedef T_ value_type;
typedef std::size_t size_type;
typedef T_ & reference;
typedef T_ const & const_reference;
typedef T_ * pointer;
typedef T_ const * const_pointer;
typedef T_ * iterator;
typedef T_ const * const_iterator;
typedef std::ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// data store
value_type data[SIZE_];
size_type size() const { return SIZE_; }
reference operator [] ( size_type idx ) { return data[idx]; }
const_reference operator [] ( size_type idx ) const { return data[idx]; }
reverse_iterator rbegin() { return reverse_iterator( end() ); }
reverse_iterator rend() { return reverse_iterator( begin() ); }
const_reverse_iterator rbegin() const { return const_reverse_iterator( end() ); }
const_reverse_iterator rend() const { return const_reverse_iterator( begin() ); }
const_reverse_iterator crbegin() const { return const_reverse_iterator( end() ); }
const_reverse_iterator crend() const { return const_reverse_iterator( begin() ); }
iterator begin() { return data; }
iterator end() { return data + SIZE_; }
const_iterator begin() const { return data; }
const_iterator end() const { return data + SIZE_; }
const_iterator cbegin() const { return data; }
const_iterator cend() const { return data + SIZE_; }
};
In this template our prof defined a bunch of typedefs, and a few of them had both a non-constant and constant version. First, I wonder what the purpose of each of the public members are, and second, I wonder what the purpose of the constant versions are, in the context of defining a data structure template.
I also notice that some of the member functions are defined as 'const' and I wonder what the purpose of that is.
I wonder what the purpose of each of the public members are.
The class contains the following:
Type aliases: Type information that is exposed from the class for public use.
The non-const typedefs are type aliases for a non-const T.
The const typedefs are type aliases for a const T.
These typedefs are useful because the user of the class might need more information about the type. By using the typedef exposed by the class, he can obtain this. Here's a good example - Consider the situation where we have a template type and we need to access the underlying iterator type. By using the exposed type alias, we can access it:
template<class Container>
void example(Container& c)
{
typename Container::iterator begin = c.begin(),
// ^^^^^^^^^^^^^^^^^^^
end = c.end();
}
I wonder what the purpose of the constant versions are.
Sometimes the user needs to use const types. Therefore using the type information that class provides makes this simple.
I also notice that some of the member functions are defined as 'const' and I wonder what the purpose of that is.
const member functions are functions that do not modify any of the classes data members.
all the typedefs aim to facilitate the use of these types,
std::size_t std::ptrdiff_t is just unsigned int typedefs.
chech here for reverse_iterator
const varialbe defined for the return value of the const version function, which is provided for the const obj, check here
member function defined as const make sure the member variable is not changed in the function body, check here
For this, I think you should try to use this template, and you may really know why it need such public members.
while we are using this template to operate on some data structure, if we want to modify some data, we need a non-constant version. On the other side, if we want to change the value of data, we need a constant version which can help us protect data.
Constant functions can help you, while you are trying to operate on some data and you do not want to modify the member data.

C++11 cast const iterator pointing to container of shared_ptr objects

I have an STL container whose element type is const std::shared_ptr<MyClass>.
I want to supply two iterator types to the user:
MyContainer::iterator
typedefed as std::vector<const std::shared_ptr<MyClass>>::iterator
(which should be the same type as std::vector<const std::shared_ptr<const MyClass>>::const_iterator
MyContainer::const_iterator
typedefed as std::vector<const std::shared_ptr<const MyClass>>::iterator
(which should be the same type as std::vector<const std::shared_ptr<const MyClass>>::const_iterator
In other words, I want the "const" to refer to the MyClass constness, not shared_ptr constness. The solution I found for getting the second iterator type is getting the first one, which is easy (e.g. using vector::begin), and then converting it to the second type using static_cast (fixme: no need to use const_cast because I'm adding constness, not removing it).
Would that be the common good-design way to achieve that, or there's a better/more common way?
typedefed as std::vector<const std::shared_ptr<MyClass>>::iterator (which should be the same type as std::vector<std::shared_ptr<const MyClass>>::const_iterator
But it probably isn't the same type. Iterators are not just pointers. If the iterator and const_iterator types are defined inside vector then they are completely unrelated types:
template<typename T>
class vector
{
class iterator;
class const_iterator;
// ...
vector<const int> is a different type to vector<int> and so their nested types are also different. As far as the compiler is concerned they are completely unrelated types, i.e. you cannot just move const around to any point in this type and get compatible types:
vector<const shared_ptr<const T>>::iterator
You cannot use const_cast to convert between unrelated types. You can use static_cast to convert a vector<T>::iterator to a vector<T>::const_iterator but it's not really a cast, you're constructing the latter from the former, which is allowed because that conversion is required by the standard.
You can convert a shared_ptr<const T> to a shared_ptr<T> with const_pointer_cast<T> but again only because it's defined to work by the standard, not because the types are inherently compatible and not because it "just works" like plain ol' pointers.
Since vector's iterators don't provide the deep-constness you want, you'll need to write your own, but it's not hard:
class MyClass { };
class MyContainer
{
typedef std::vector<std::shared_ptr<MyClass>> container_type;
container_type m_cont;
public:
typedef container_type::iterator iterator;
class const_iterator
{
typedef container_type::const_iterator internal_iterator;
typedef std::iterator_traits<internal_iterator> internal_traits;
const_iterator(internal_iterator i) : m_internal(i) { }
friend class MyContainer;
public:
const_iterator() { }
const_iterator(iterator i) : m_internal(i) { }
typedef std::shared_ptr<const MyClass> value_type;
typedef const value_type& reference;
typedef const value_type* pointer;
typedef internal_traits::difference_type difference_type;
typedef internal_traits::iterator_category iterator_category;
const_iterator& operator++() { ++m_internal; return *this; }
const_iterator operator++(int) { const_iterator tmp = *this; ++m_internal; return tmp; }
reference operator*() const { m_value = *m_internal; return m_value; }
pointer operator->() const { m_value = *m_internal; return &m_value; }
// ...
private:
internal_iterator m_internal;
mutable value_type m_value;
};
iterator begin() { return m_cont.begin(); }
const_iterator begin() const { return const_iterator(m_cont.begin()); }
// ...
};
That iterator type is mising a few things (operator--, operator+) but they're easy to add, following the same ideas as already shown.
The key point to notice is that in order for const_iterator::operator* to return a reference, there needs to be a shared_ptr<const MyClass> object stored as a member of the iterator. That member acts as a "cache" for the shared_ptr<const MyClass> value, because the underlying container's real elements are a different type, shared_ptr<MyClass>, so you need somewhere to cache the converted value so a reference to it can be returned. N.B. Doing this slightly breaks the iterator requirements, because the following doesn't work as expected:
MyContainer::const_iterator ci = c.begin();
const shared_ptr<const MyClass>& ref = *ci;
const MyClass* ptr = ref.get();
++ci;
(void) *ci;
assert( ptr == ref.get() ); // FAIL!
The reason the assertion fails is that *ci doesn't return a reference to an underlying element of the container, but to a member of the iterator, which gets modified by the following increment and dereference. If this behaviour isn't acceptable you'll need to return a proxy from your iterator instead of caching a value. Or return a shared_ptr<const MyClass> when the const_iterator is dereferenced. (The difficulties of getting this 100% right is one of the reasons STL containers don't try to model deep constness!)
A lot of the effort of defining your own iterator types is done for you by the boost::iterator_adaptor utility, so the example above is only really useful for exposition. With that adaptor you'd only need to do this to get your own custom iterator types with the desired behaviour:
struct iterator
: boost::iterator_adaptor<iterator, container_type::iterator>
{
iterator() { }
iterator(container_type::iterator i) : iterator_adaptor(i) { }
};
struct const_iterator
: boost::iterator_adaptor<const_iterator, container_type::const_iterator, std::shared_ptr<const MyClass>, boost::use_default, std::shared_ptr<const MyClass>>
{
const_iterator() { }
const_iterator(iterator i) : iterator_adaptor(i.base()) { }
const_iterator(container_type::const_iterator i) : iterator_adaptor(i) { }
};
boost::iterator_adaptor makes it pretty easy to define your own iterator types based on another iterator type. So you can set it up so that *iter is a const shared_ptr<MyClass>& or const shared_ptr<const MyClass>& as desired.
Though in the const_iterator case, dereferencing can't return a const shared_ptr<const MyClass>& if what you actually have is shared_ptr<MyClass>. So we'll define const_iterator::reference as just shared_ptr<const MyClass> and return by value.
#include <boost/iterator/iterator_adaptor.hpp>
class MyContainer {
public:
class iterator;
class const_iterator;
class iterator :
public boost::iterator_adaptor<
iterator, // This class, for CRTP
std::vector<const std::shared_ptr<MyClass>>::const_iterator,
// Base type
const std::shared_ptr<MyClass> > // value_type
{
public:
iterator() {}
iterator(const iterator&) = default;
private:
friend class MyContainer; // allow private constructor
friend class boost::iterator_core_access; // allow dereference()
explicit iterator(base_type iter) : iterator_adaptor(iter) {}
const std::shared_ptr<MyClass>& dereference() const
{ return *base_reference(); }
};
class const_iterator :
public boost::iterator_adaptor<
const_iterator, // This class, for CRTP
std::vector<const std::shared_ptr<MyClass>>::const_iterator,
// Base type
const std::shared_ptr<const MyClass>, // value_type
boost::use_default, // difference_type
std::shared_ptr<const MyClass> > // reference_type
{
public:
const_iterator();
const_iterator(const const_iterator&) = default;
// Implicit conversion from iterator to const_iterator:
const_iterator(const iterator& iter) : iterator_adaptor(iter.base()) {}
private:
friend class MyContainer; // allow private constructor
friend class boost::iterator_core_access; // allow dereference()
explicit const_iterator(base_type iter) : iterator_adaptor(iter) {}
std::shared_ptr<const MyClass> dereference() const
{ return *base_reference(); }
};
iterator begin() { return iterator(mVec.begin()); }
iterator end() { return iterator(mVec.end()); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
const_iterator cbegin() const { return const_iterator(mVec.begin()); }
const_iterator cend() const { return const_iterator(mVec.end()); }
private:
std::vector<const std::shared_ptr<MyClass>> mVec;
};
shared_ptr and other standard smart pointers are not designed with deep-constness in mind. They are trying to be as close to raw pointer usage as possible, and raw pointer's const-ness does not affect the pointee's const-ness.
Andrei Alexandrescu's Loki::SmartPtr (described in his Modern C++ Design) implements reference counting and deep const-ness as policies, which would give you the effect you're looking for. If you don't mind switching to a non-standard smart pointer in order to get non-standard behavior, that may be one way to go.

own iterator class not working with std::binary_search

I found a lot of answers here to the topic, but I couldn't get my code to run.
EDIT:
The posted example now works after introducing the missing things. In hope some one can use the example as basis for own experiments. I also introduced the missing things to use this example as random access iterator. It works much more efficient with binary_search algos.
If I have to write my own iterator I struggle with value_type and other "specials" to operate with .
I read a lot of articles here how to NOT write iterators but could not get any working example. Especially I read that I should not derive from iterator. So I will ask stupid again:
How can I define the value_type of my iterator. It did not work with in class definition and also did not work with defining manually over type_traits struct. No idea how to continue...
#include <iostream>
#include <algorithm>
#include <type_traits>
#include <iterator>
using namespace std;
int data[]= { 1,4,7,9,11,20,28 }; //Sorted data
template < typename T >
class MyIter
{
int offset;
T* base;
public:
typedef int value_type;
//add the following lines after reading the answers -> it works!
typedef std::ptrdiff_t difference_type;
typedef T * pointer;
typedef T & reference;
typedef std::forward_iterator_tag iterator_category;
// if you want to use as random access iterator:
// typedef std::random_access_iterator_tag iterator_category;
public:
MyIter( T* _base, int _offset) : base(_base), offset(_offset) {}
MyIter() {}
bool operator !=( const MyIter& rhs)
{
T* tmp1= base+offset;
T* tmp2= rhs.base + rhs.offset;
return tmp1 != tmp2;
}
MyIter operator++(int)
{
MyIter tmp(*this);
offset++;
return tmp;
}
T operator*()
{
return *(base+offset);
}
// Addition: if used as random access iterator you must provide:
int operator-(const MyIter& rhs)
{
return offset-rhs.offset;
}
MyIter operator+=(int off)
{
offset+=off;
return *this;
}
};
typedef MyIter<int> iterType ;
int main()
{
cout << "ok" << endl;
pair<iterType, iterType> bounds;
MyIter<int> start( data,0);
MyIter<int> ende ( data,7);
bounds = equal_range( start, ende, 28 );
for ( iterType it= bounds.first; it!=bounds.second; it++)
{
cout << "Found " << *it << endl;
}
return 0;
}
You are missing a few definitions in addition to value_type that the standard library requires from iterators:
typedef std::ptrdiff_t difference_type;
typedef T * pointer;
typedef T & reference;
typedef std::forward_iterator_tag iterator_category;
Alternatively, inheriting from std::iterator<std::forward_iterator_tag, T> will give you these. I don't know where you read that you shouldn't do that, but that's exactly what std::iterator is for.
Additionally, you're missing a pre-increment operator:
MyIter operator++()
{
++offset;
return *this;
}
and also -> and == operators. Also, the dereference operator should probably return a reference to allow *it = 42, with a const overload returning a value or const reference.
std::binary_search requires a random access iterator. Which
means that the iterator must support addition and subtraction
(+, +=, - and -=), with exactly the same semantics as
a pointer. And any number of algorithms will also expect
a number of typedef in the iterator: deriving from
std::iterator is the easiest way to get them. (Technically,
what the standard requires is that std::iterator_traits yield
the correct values, so you could explicitly instantiate it for
your iterator. But its default implementation picks up typedef
in the iterator class.)
EDIT:
Rereading your post: you definitly should publically derive from std::iterator. Whoever says otherwise is wrong.
You are missing several essential type members and the pre-increment operator (as well as a bunch of other dereference and comparison operators as pointed out by #MikeSeymour). Add thise to your class definition (note that I rewrote the post-increment operators in terms of the currently missing pre-increment operator) to get your binary_search going
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
MyIter& operator++()
{
++offset;
return *this;
}
MyIter operator++(int)
{
MyIter tmp(*this);
++*this; // NOTE this will call the other operator++
return tmp;
}
Output on LiveWorkSpace As pointed out by #JamesKanze, these missing typedefs are provided by inheriting from std::iterator<std::forward_iterator_tag, T>.