views:

533

answers:

10

As an extension to this question Are const_iterators faster?, I have another question on const_iterators. How to remove constness of a const_iterator? Though iterators are generalised form of pointers but still const_iterator and iterators are two different things. Hence, I believe, I also cannot use const_cast<> to covert from const_iterator to iterators.

One approach could be that you define an iterator which moves 'til the element to which const_iterator points. But this looks to be a linear time algorithm.

Any idea on what is the best way to achieve this?

+1  A: 

You can subtract the begin() iterator from the const_iterator to obtain the position the const_iterator is pointing to and then add begin() back to that to obtain a non-const iterator. I don't think this will be very efficient for non-linear containers, but for linear ones such as vector this will take constant time.

vector<int> v;                                                                                                         
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
vector<int>::iterator it = v.begin() + (ci - v.begin());
cout << *it << endl;
*it = 20;
cout << *ci << endl;

EDIT: This appears to only work for linear (random access) containers.

marcog
That will only work if you have a suitable operator defined for subtracting iterators from const iterators. AFAIK there is no such thing.
Visage
I just tried the above code and it works. :)
marcog
It might work for vector(Random Access iterator). It may not work for list and other container.
aJ
@Visage: You don't need an suitable operator, in this case you are subtracting a const_iterator from a const_iterator, getting an integer offset, and adding it to an iterator. Perfectly valid, and works as it would be expected to work.
X-Istence
@aJ You're quite right, I just checked.
marcog
More specifically, this will only work with a Random Access Iterator since it is the concept that defines the necessary operations. Take a look at the SGI docs (http://www.sgi.com/tech/stl/RandomAccessIterator.html) for what I consider the best description.
D.Shawley
+4  A: 

Unfortunately linear time is the only way to do it:

iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));

where iter and constIter are suitable typedefs and d is the container over which you are iterating.

Visage
Implementations are allowed to (and do) specialize std::advance and std::distance for random access iterators so that this can be constant time for some containers.
Charles Bailey
Actually, this should be constant time for (well-implemented) random access iterators. See http://www.aristeia.com/Papers/CUJ_June_2001.pdf.
Pontus Gagge
+5  A: 

Can I suggest getting hold of a copy of Scott Meyers' excellent book Effective STL, where issues like this and the others you have raised are discussed in detail. Scott spends three pages describing the solution to your current question.

anon
That also suggest the linear time, I guess. Is that the only way to achieve?
aJ
I think your comment is meant for one of the other answers
anon
I was referring to topic from Effective STL book. It suggests linear time algorithm.
aJ
Yep, that's the only way to do it. But if you need a non-const iterator, why not use one in the first place?
anon
aJ
Well, why not do a const cast on the container reference then? You can then use an ordinary iterator to do the delete. You might also want to see if the "mutable" keyword is applicable in this case.
anon
casting the container idea is fine. But I wanted to check is there a method to remove constness of const_iterator only when certain condition is met. Mutable would work only for member function of the class, which are const.
aJ
why not take a non-const container in the first place?
Johannes Schaub - litb
Please add a few line summary when refering to another location, especially when that location is not a web link, but a book.
Catskul
A: 

You could also use find to search for the element (if there are no duplicate elements):

iterator it=find(container.begin(), container.end(), *constit);
tstenner
+1  A: 

This may not be the answer you wanted, but somewhat related.

I assume you want to change the thing where the iterator points to. The simplest way I do is that const_cast the returned reference instead.

Something like this

const_cast<T&>(*it);

leiz
Some functions like erase etc. require a const_iterator, so this wouldn't work.
tstenner
You mean that erase takes a non const iterator, right?If that is the case, why do you use const_iterator at first place? most of time this kinda const cast I needed was for debugging propers.
leiz
A: 

you can convert your const iterator value pointer to a non const value pointer and use it directly something like this

    vector<int> v;                                                                                                         
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(2);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
*const_cast<int*>(&(*ci)) = 7;
cout << *ci << endl;
Ankit
+1  A: 

I believe this conversion is not needed in good designed program.

If you need do this - try redesign code.

As workaround you can do next:

typedef std::vector< size_t > container_type;
container_type v;
// filling container code 
container_type::const_iterator ci = v.begin() + 3; // set some value 
container_type::iterator i = v.begin();
std::advance( i, std::distance< container_type::const_iterator >( v.begin(), ci ) );

But I'm think that sometimes this conversion is impossible, because your algorithms can haven't access to container.

bb
+1 on refactoring. Moreover when using const_iterators is intended as a performance hack.
David Rodríguez - dribeas
+1  A: 

In the answers to your previous post, there were a couple of people, me included, that recommended using const_iterators instead for non-performance related reasons. Readability, traceability from the design board to the code... Using const_iterators to provide mutating access to a non-const element is much worse than never using const_iterators at all. You are converting your code into something that only you will understand, with a worse design and a real maintainability pain. Using const just to cast it away is much worse than not using const at all.

If you are sure you want it, the good/bad part of C++ is that you can always get enough rope to hang yourself. If your intention is using const_iterator for performance issues, you should really rethink it, but if you still want to shoot your foot off... well C++ can provide your weapon of choice.

First, the simplest: if your operations take the arguments as const (even if internally apply const_cast) I believe it should work directly in most implementations (even if it is probably undefined behavior).

If you cannot change the functors, then you could tackle the problem from either side: provide a non-const iterator wrapper around the const iterators, or else provide a const functor wrapper around the non-const functors.

Iterator façade, the long road:

template <typename T>
struct remove_const
{
    typedef T type;
};
template <typename T>
struct remove_const<const T>
{
    typedef T type;
};

template <typename T>
class unconst_iterator_type
{
    public:
        typedef std::forward_iterator_tag iterator_category;
        typedef typename remove_const<
                typename std::iterator_traits<T>::value_type
            >::type value_type;
        typedef value_type* pointer;
        typedef value_type& reference;

        unconst_iterator_type( T it )
            : it_( it ) {} // allow implicit conversions
        unconst_iterator_type& operator++() {
            ++it_;
            return *this;
        }
        value_type& operator*() {
            return const_cast<value_type&>( *it_ );
        }
        pointer operator->() {
            return const_cast<pointer>( &(*it_) );
        }
        friend bool operator==( unconst_iterator_type<T> const & lhs,
                unconst_iterator_type<T> const & rhs )
        {
            return lhs.it_ == rhs.it_;
        }
        friend bool operator!=( unconst_iterator_type<T> const & lhs,
                unconst_iterator_type<T> const & rhs )
        {
            return !( lhs == rhs );
        }
    private:
        T it_;  // internal (const) iterator
};
David Rodríguez - dribeas
+2  A: 

Scott Meyer's article on preferring iterators over const_iterators answers this. Visage's answer is the only safe alternative, but is actually constant time for well-implemented random access iterators, and linear time for others.

Pontus Gagge
The article is pre-2003 standard (back from 2001). I'd like to see an updated revision after the 2003 changes to the standard
David Rodríguez - dribeas
A: 

Is it possible to specify some part of the data the iterator is pointing to as mutable?

Niki Yoshiuchi