0lt
0lt

Reputation: 313

Const method returning non-const reference compiles

I have a simple Vector class with indexing operator implemented. Coming from this and other related questions, I am unsure as to why the following code compiles:

int main()
{
    const Vector A(5);
    cout << "A :" << A << endl;
    A[0] = 5;
    cout << "A: " << A << endl;
}

Vector.h

#pragma once
#include <iostream> 
#include <functional>

namespace vector
{
    class Vector
    {
        friend std::ostream& operator<<(std::ostream&, const Vector&);

        int n;
        int *arr; 
    public:
        Vector(int = 0); 
        ~Vector();
        Vector(const Vector&);
        Vector& operator=(const Vector&);
    private:
        void copy(const Vector&);
    public:
        int& operator[](const int) const;   
    };
}

Vector.cpp

#include "Vector.h"
#include <algorithm>
#include <utility>
#include <functional>


namespace vector
{ 
    Vector::Vector(int n) : n(n), arr(new int[n])
    {
        std::fill(arr, arr + n, 0);
    }

    Vector::~Vector()
    {
        n = 0;
        delete[] arr;
    }

    void Vector::copy(const Vector& other)
    {
        arr = new int[n = other.n];
        std::copy(other.arr, other.arr + n, arr);
    }

    Vector::Vector(const Vector& other)
    {
        copy(other);
    }

    Vector& Vector::operator=(const Vector& other)
    {
        if (this != &other)  
        {
            this->~Vector();
            copy(other);
        }
        return *this;
    }

    int& Vector::operator[](const int index) const
    {
        return arr[index];
    }

    std::ostream& operator<<(std::ostream& stream, const Vector& vec)
    {
        for (int i = 0; i < vec.n; i++)
            stream << vec.arr[i] << " ";

        return stream;
    }

}

Output:

A: 0 0 0 0 0
A: 5 0 0 0 0

How could a const method returning a non-const reference (later used to change the previously const object) even compile?

Upvotes: 3

Views: 1030

Answers (2)

AndreyS Scherbakov
AndreyS Scherbakov

Reputation: 2788

const in a method declaration only means that the method has read only access to the instance itself (as if it receives const MyType *this rather than MyType *this). If arr is a pointer to int in your class, it will be respectively considered as int * const when used inside a const method. But please note that it's not the same as const int * ! That's why dereferencing it yields an int&, not const &int .

Upvotes: 0

songyuanyao
songyuanyao

Reputation: 172924

In short, it's your responsibility.

In const member function, only the data member itself becomes const. For arr (which is supposed to be of type int*) it'll become int * const (i.e. const pointer), not int const * (i.e. pointer to const); i.e. the pointer becomes const but the pointee doesn't. So technically it's possible to return a non-const reference to the pointee, even it might not make much sense in fact.

You'd better to overload on operator[], like most STL containers do. e.g.

// const version
int const & Vector::operator[](const int index) const 
{
    return arr[index]; 
}

// non-const version
int & Vector::operator[](const int index)
{
    return arr[index]; 
}

Upvotes: 11

Related Questions