Alexander Bily
Alexander Bily

Reputation: 975

Const correctness in C++

I have simple data structure called array (similar to std::array). array class have method called all(). Here are method declarations:

const range<const_type_pointer> all() const;
range<type_point> all();

range is class template, which is constructed by two iterators. Here is simplified version of range class declaration:

template <typename Iterator>
class range {

    typedef typename iterator_traits<Iterator>::type_value type_value;
    typedef typename iterator_traits<Iterator>::type_reference type_reference;
    typedef typename iterator_traits<Iterator>::type_pointer;

    range(Iterator begin, Iterator end);
// methods & algorithms

// data members

    mutable Iterator _begin;
    mutable Iterator _end;
};

So basically, if I call method all on const array object, it should call const overload of method and return const range. Now, in my algorithms section, I have simple algorithm with following signature:

    template <typename UnaryFunction>
    range forEach(UnaryFunction function);

Then I tried following test:

void test1(const array<int, 10>& array)
{
    auto r = array.all();
    r.forEach([](int i) { std::cout << i << " "; });
}

And second one:

void test2(const array<int, 10>& array)
{
    auto r = array.all();
    r.forEach([](int& i) { ++i; });
}

In first case, where I was just printing variable i, compiler did not complained, even though I called non-const range method on const range object. In second case, compiler complained. Is this behaviour standard confornant?

As a compiler, I am using MSVS compiler.

Upvotes: 2

Views: 120

Answers (2)

SergeyA
SergeyA

Reputation: 62613

First. Sice you are returning by value, it doesn't really make any difference if you are returning const range or range.

Second. auto r = array.all(); creates a copy of whatever was returned by all. Your r is a non-const object, and non-const forEach is used. But since the iterator is const in the second version, you can't modify the iterable.

Upvotes: 1

auto works just like template argument deduction, which means that it drops top-level references and top-level const & volatile qualifiers. In other words, your r is of type range<const_pointer_type> in both cases.

Returning a const-qualified object should only be done in very special circumstances when you understand all details of its behaviour and really know that you want them.

Normally, you should just return objects without cv-qualifiers. It will play nicer with move semantics, and will not lead to incorrect expectations.

Upvotes: 1

Related Questions