Search code examples
c++operator-overloadingoperatorsreadonlyread-write

Why isn't the read only [] operator used?


I'm currently writing an Polynomial-class in C++, which should represent an polynomial of the following form:

p(x) = a_0 + a_1*x^1 + a_2*x^2 + ... + a_i*x^i

where a_0, ..., a_i are all int's.

The class internally uses an member variable a_ of typestd::vector<int> to store the constant factors a_0, ..., a_i. To access the constant factors the operator[] is overloaded in the following way:

Read and write:

int &operator[](int i)
{
  return a_.at(i);
}

This will fail when trying to change one of the factors a_i with:

i > degree of polynomial = a_.size() - 1

Read-only:

int operator[](int i) const
{
  if (i > this->degree()) {
    return 0;
  }

  return a_.at(i);
}

The slightly different implementation allows rather comfortable looping over the factors of two different sized polynomials (without worrying about the degree of the polynomial).

Sadly I seem to miss something here, since the operator+-overloading (which makes use of this comfortable read-only-operator[]) fails.

operator+-overloading:

Polynomial operator*(const Polynomial &other) {
  Polynomial res(this->degree() + other.degree());

  for (int i = 0; i <= res.degree(); ++i) {
    for (int k = 0; k <= i; ++k) {
      res[i] += (*this)[k] * other[i-k];
    }
  }

  return res;
}

Don't mind the math involved. The important point is, that the i is always in the range of

0 <= i < res.a_.size()

thus writing to res[i] is valid. However (*this)[k] and other[i-k] try to read from indices which don't necessarily lay in the range [0, (*this).a_.size() - 1].

This should be fine with our read-only-implementation of the operator[] right? I still get an error trying to access a_ at invalid indices. What could cause the compiler to use the read-write-implementation in the line:

res[i] += (*this)[k] * other[i-k]; 

Especially the part on the right side of the equality.

I'm certain the error is caused by the "wrong" use of the read-and-write-operator[]. Because with an additional check fixes the invalid access:

if (k <= this->degree() && i-k <= other.degree()) {
  res[i] += (*this)[k] * other[i-k];
}

What am I missing with the use of the operator[]-overloading? Why isn't the read-only-operator[] used here?


Solution

  • (*this)[k] is using the non-const this as the function containing it is not const.

    Hence the non-const overload of [] is preferred by the compiler.

    You could get round this using an ugly const_cast, but really you ought to keep the behaviour of the two versions of the [] operator as similar as possible. Besides, the std::vector overload of [] doesn't insist on the index being bounds checked, as opposed to at which must be. Your code is a deviation from this and therefore could confuse readers of your code.