I have a constant iterator class which contains the following methods for overloading several operator functions
self_reference operator=( const SDAL_Const_Iter& src ) {
index = src.index;
return *this;
}
self_reference operator++() {
index = index + 1;
return *this;
}
self_type operator++(int) {
SDAL_Const_Iter results = *this;
++index;
return results;
}
The index variable is of type const int.
My compiler is complaining that I am attempting to modify a constant object (More specifically, "Error C2166: l-value specifies constant object"), which I am aware of; however, I see no other way of overloading these functions. Can someone please elaborate on how to go about writing these overloads without causing compiler issues?
I believe the problem is in const int as index variable.
A constant iterator should not allow non-const access to the container's data. The iterator itself, though, is changeable (it has to be able to iterate). Changing index to int should fix the problem.
Related
I am trying to implement a binary search tree container. At the moment I have to implement a find() function that is able to return an iterator or a constant iterator. I choose to overload the find function to accomodate both possibilities
MyIterator<treepair> find(const key& x)
{
return tree_search<MyIterator<treepair>>(root,x);
}
const_MyIterator<treepair> find(const key& x) const
{
return tree_search<const_MyIterator<treepair>>(root,x);
}
Then the function tree_search recursively finds the node that contains the wanted key by percurring the tree:
template<typename iterator>
iterator tree_search(Node<treepair>* x, const key& y) const
{
if(x == nullptr)
{
std::cout<<"element not found"<<std::endl;
iterator x = end();//HERE I HAVE A PROBLEM
return x;
}
else if (y == x->value.first)
{
iterator i{x,tree_maximum()};
std::cout<<"element found"<<std::endl;
return i;
}
if(y < x->value.first)
return tree_search<iterator>(x->left,y);
else return tree_search<iterator>(x->right,y);
}
Now the end() function is overloaded to give both a const_iterator and a regular iterator:
MyIterator<treepair> end(){
return MyIterator<treepair>{nullptr,tree_maximum()};
}
const_MyIterator<treepair> end() const{
return const_MyIterator<treepair>{nullptr,tree_maximum()};
}
however I receive this error
test_on_iterators.cc:508:12: error: conversion from ‘const_MyIterator<std::pair<int, int> >’ to non-scalar type ‘MyIterator<std::pair<int, int> >’ requested
iterator x = end();
Is this error due to a requirement in the conversion between the types? Isn't the compiler supposed to choose the wanted end() function according to the iterator type it has to produce?
Isn't the compiler supposed to choose the wanted end() function according to the iterator type it has to produce?
No.
tree_search() is a const method. That means its this pointer is pointing at a const object (even if the object tree_search() is called on is not really const).
As such, when tree_search() internally calls end(), it calls the overload that is callable on a const object. That overload returns a const_MyIterator. Then tree_search() tries to assign that const_MyIterator to a non-const MyIterator, which is where you get the error since there is no conversion defined from const_MyIterator to MyIterator.
You need to make x be a const_MyIterator to match what the const version of end() returns.
You should also make tree_search() return a const_MyIterator as well, instead of returning a non-const iterator. If you want tree_search() to return a non-const Iterator, then don't declare it as a const method.
given the following code:
#include <set>
using std::set;
class Pool {
set<int> s;
public:
typedef typename set<int>::iterator Iterator;
const Iterator& begin() const {
return s.begin(); //** error
}
};
Why I get the following error (I understand the meaning of the error, but, I don't understand why I get it in this case)?
returning reference to temporary [-Werror=return-local-addr]
How can I fix it?
The set<...>::begin function returns its iterator by value. Since you do not store that value anywhere, it's a temporary value, and you can't really have references to temporary values.
The simple solution is for your function to also return by (non-const) value.
const Iterator& begin() const {
return s.begin(); //** error
}
is illegal because the result of s.begin() is a temporary object and therefore you can't return a reference to it. Maybe if you look at this equivalent code it will be clearer?
const Iterator& begin() const {
Iterator it = s.begin();
return it; //** error
}
Returning a const reference to an iterator doesn't make much sense anyway as you wont be able to move the location that the iterator points to. You should always return iterators by value, this way the caller is free to make copies of the iterator and modify their location. For example if you could get your code to compile the following calling code would not work:
Pool p;
const Pool::Iterator& it = p.begin();
++it; //error it is constant
The user could fix their code by copying your returned reference into a new object:
Pool p;
Pool::Iterator it = p.begin();
++it; //no error
As your users wont be able to use the reference you can't return its better just to return by value:
const Iterator begin() const {
return s.begin();
}
Note that std::set is not like most other containers and doesn't allow modification of the values via its iterators: https://en.cppreference.com/w/cpp/container/set/begin
Because both iterator and const_iterator are constant iterators (and may in fact be the same type), it is not possible to mutate the elements of the container through an iterator returned by any of these member functions.
Is this:
auto& ref1 = *it++;
ref1 = expression; // (1)
one of the required semantics of a forward iterator? And what about a random access iterator?
auto& ref1 = it[3];
ref1 = expression; // (2)
According to cppreference, a forward iterator is required to:
// Return reference, which equals to (const) value_type &
*it++ === value_type&
and for a random access iterator:
it[n] === *(it + n)
which is the same situation, which means that in both situations you are dereferencing a temporary (the iterator). In my case, my iterator stores by copy an index which allows to access a container which doesn't provide direct access to the stored elements, only through the index.
That works fine:
*it++ = value;
since the temporary copy of it has sentence scope.
But in this case:
type& val = *it++;
val = 3;
we get undefined behaviour, since the copy is already destroyed in the second line.
In my situation, I have a QModelIndex wrapper to get data/save from/to a QAbstractItemModel. The model only gives you copies of the QVariants stored on the model.
My wrapper class (the value_type with the operator= overloaded) saves an instance of a QModelIndex (to manipulate the model), and the iterator an instance of that wrapper. So, if the iterator is destroyed, the wrapper and the index too.
I think I can solve both problems as far as lines (1) and (2) don't need to be supported.
NOTE: My implementation is more or less like that (simplified):
// The value type
struct index
{
QModelIndex qidx;
index& operator=(QVariant const& val)
{
if (qidx.isValid())
qidx.model()->setData(qidx, val);
return *this;
}
};
// Private class actually. The "movements" cannot be done
// over the value type because it will cause, in functions
// returning references to the value type, to increase the chaos.
// So, I make the index points to different model items using
// this class.
struct index_manipulator
{
QModelIndex& qidx;
void move(int rows, int cols)
{
if (qidx.isValid())
qidx = qidx.model()->index(qidx.row() + rows,
qidx.column() + cols);
}
};
struct index_safe_ref
{
mutable index idx;
operator index&() const { return idx; }
};
struct my_row_it
{
index idx;
index_manipulator manip = {idx.qidx};
my_row_it(QAbstractItemModel* m, int col)
: idx(m ? m->index(0, col) : QModelIndex())
{}
index& operator*() const { return idx; }
my_row_it operator++(int) const
{
auto copy = it;
manip.move(1, 0);
return copy;
}
index_safe_ref my_row_it::operator[](difference_type n) const
{
auto it = it + n; // Operator+ is over there.
return { it.idx };
}
};
A stashing iterator (that is, an iterator that returns a reference to something within itself) is never a valid forward iterator.
Iterators in general must be CopyConstructible ([iterator.iterators]/2.1, which requires, among other things, that a copy of the iterator be equivalent to the original. It follows that a forward iterator and its copy must necessarily compare equal, and [forward.iterators]/6 requires that that for two equal dereferenceable iterators a and b, *a and *b must be bound to the same object, which cannot be satisfied for stashing iterators.
If you need to ignore a requirement, I suggest ignoring the one that says reference must be an actual reference type, turning your stashing iterator into a proxy iterator. There's established practice for that in the standard library (vector<bool>::iterator) and any breakage is likely to be a loud compile-time error, rather than silent runtime mischief.
This is covered by a general statement about iterators:
Destruction of an iterator may invalidate pointers and references previously obtained from that iterator.
§24.2.1/9 N3337
But, as T.C. points out in the other answer your iterator cannot be a valid forward iterator (or anything more strict then) if you return a reference to an object contained within the iterator object.
I see two solutions: Return that index object by value, or return a reference to a heap allocated index object.
As a note, an input iterator needs to support this:
value_type temp = *iterator++; // or *iterator; ++iterator;
// use temp
So in your case this must work (but should as far as I can see):
index temp = *iterator++;
temp = expression.
This is not the same as line (1) because above code involves a conversion to the value_type (and not a reference to it).
I want to write my own 2d array class. I want the class to be able to assign a value to an element like this.
a(0,0) = 1
I know this must be possible because I can do it with the matrix classes from blaze and eigen. My first idea was to overload the function operator (), which already works great to access the elements. When I try to assign a value with a(0,2) = 0; I get a compiler error.
lvalue required as left operand of assingment
What operator do I have to overload that the assignment also works?
You need to build a function with this prototype:
T& operator()(std::size_t, std::size_t);
Where T is your element type. This function needs to return a reference to an element in the array. This allows you to modify the value of the element via that reference in the caller.
As well as the above, you ought to provide the function
const T& operator()(std::size_t, std::size_t) const;
for read-only element access. I've rather dogmatically insisted on std::size_t for your indexing. In reality, you might want a typedef of your own to stand in for the index type.
You need to provide two overloads - one const and another one not, returning a reference. For example:
template <typename TVal> class val {
std::map<int, TVal> values;
public:
// the distinction is between a const version ...
TVal operator()(int key) const {
auto found = values.find(key);
if (found != values.end())
return found->second;
return TVal();
}
// ... and a non-const, returning a reference
TVal& operator()(int key) {
return values[key];
}
};
and then you can use it as follows:
val<int> v;
v(1) = 41;
v(1)++;
std::cout << v(1) << std::endl; // -> 42
std::cout << v(2) << std::endl; // -> 0
Please post the compile-error, for others to see and precisely answer it.
Having said that, I am pretty sure that it is because you are not returning a reference from your operator.
In his The C++ Programming Language Stroustrup gives the following example for inc/dec overloading:
class Ptr_to_T {
T* p;
T* array ;
int size;
public:
Ptr_to_T(T* p, T* v, int s); // bind to array v of size s, initial value p
Ptr_to_T(T* p); // bind to single object, initial value p
Ptr_to_T& operator++(); // prefix
Ptr_to_T operator++(int); // postfix
Ptr_to_T& operator--(); // prefix
Ptr_to_T operator--(int); // postfix
T&operator*() ; // prefix
}
Why prefix operators return by reference while postfix operators return by value?
Thanks.
The postfix operator returns a copy of the value before it was incremented, so it pretty much has to return a temporary. The prefix operator does return the current value of the object, so it can return a reference to, well, its current value.
To understand better, you have to imagine (or look at) how are these operators implemented. Typically, the prefix operator++ will be written more or less like this:
MyType& operator++()
{
// do the incrementation
return *this;
}
Since this has been modified "in-place", we can return a reference to the instance in order to avoid a useless copy.
Now, here's the code for the postfix operator++:
MyType operator++(int)
{
MyType tmp(*this); // create a copy of 'this'
++(*this); // use the prefix operator to perform the increment
return tmp; // return the temporary
}
As the postfix operator returns a temporary, it has to return it by value (otherwise, you'll get a dangling reference).
The C++ Faq Lite also has a paragraph on the subject.
Suppose I use overloaded preincrement to increment a private member. Doesn't returning a reference to a private member turns the ++private_var expression to an lvalue thus making it possible to modify the private member directly?