bluescarni
bluescarni

Reputation: 3997

Is this a valid usage of ``const_cast``?

The C++11 standard has changed the signature of the erase() methods of standard containers: they now accept const_iterators instead of iterators. The rationale is explained in this document:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf

Now, if one implements std::vector<T> in a straightforward way, it is possible to use directly const T * and T * as const and mutable iterator types respectively. So in the erase() method we might have code like this:

iterator erase(const_iterator it)
{
    ...
    for (; it != end() - 1; ++it) {
        // Destroy the current element.
        it->~T();
        // Move-init the current iterator content with the next element.
        ::new (static_cast<void *>(it)) T(std::move(*(it + 1))); // FAIL
    }
    ...
}

The problem now is that, since it is a const pointer, the static cast will fail.

Is it legal in this case to cast away the constness from it? Note that it never points to a const object (the objects stored in the vector are never const), and that the calling method (erase()) is not const as well.

EDIT: thanks for all the replies. I wanted to respond here to some comments below.

This code comes from a custom vector class (with a similar interface to std::vector) that implements the small buffer optimisation on top of an unrestricted union. The iterators are naked pointers because they need to be the same type both when the vector is using static storage and when it is using dynamic storage, and this seems the most natural way of achieving such result.

The cast to void * is just a matter of habit and consistency within the codebase when interacting with unitialised storage.

Upvotes: 4

Views: 222

Answers (1)

Benjamin Lindley
Benjamin Lindley

Reputation: 103693

Since erase is non-const, yes, you can safely cast away const on the element. However, note that this is not necessary, since a non-const iterator can be obtained from the const iterator:

iterator non_const = begin() + (it - begin());

And that can be used to iterate over the vector.

Upvotes: 6

Related Questions