Does a const member function call the non-const version, or is it recursive?

218 Views Asked by At

For defining a second const version of a function, is it guaranteed safe to do this? It looks like it would have infinite recursion as I want to return const but the other function which I mean to call is non-const.

It works with g++ but I worry that this is unsafe.

#include <iostream>

using namespace std;

class test {
public:
   int* doSomething(int a) {
      int* someInt = new int(a);

      return someInt;
   }

   const int* doSomething(int a) const {
      return doSomething(a);
   }
};

int main() {
   test a;

   cout << *a.doSomething(12345) << endl;

   return 1;
}
2

There are 2 best solutions below

4
On BEST ANSWER

Not quite: as @Pete Becker has pointed out in the comments, if you had called the const version that will recurse:

class test {
public:
   int* doSomething(int a) {
      int* someInt = new int;
      *someInt = a;
      return someInt;
   }

   const int* doSomething(int a) const {
      return doSomething(a);
   }
};

int main() {
   const test a;
   // You're not in for a good time:
   a.doSomething(12345);
   return 1;
}

When providing const and non-const versions of a function that requires duplicated code, it's best to implement the const version, then have the non-const version call it in a specific way.

From Scott Myers Effective C++ - Third Edition:

When const and non-const member functions have essentially identical implementation, code duplication can be avoided by having the non-const version call the const version

Scott Myers goes on to provide a safe means for doing this:

const int* doSomething(int a) const
{
   int* someInt = new int;
   *someInt = a;
   return someInt;
}

int* doSomething(int a)
{
   return const_cast<int*>(static_cast<const Test&>(*this).doSomething());
}

In the non-const version, there are two casts: the static_cast basically turns this into const this, where the const_cast casts away the const-ness of the return. This is safe to do, because to call the non-const version, you must've had a non-const this.

However, if you are just providing access to a member, it's simple and easier to read to just have the following:

class TestAccess;
class Test
{
    TestAccess& t;
public:
    const TestAccess& getA() const { return t; }
    TestAcess& getA() { return t; }
};
5
On

In this case the compiler is always going to pick the not const version of the function, is not even calling the const one. Otherwise the compiler will not compile, you are braking the constenss. For example I modified quickly the code:

#include <iostream>

using namespace std;

class test {
public:
    int* doSomething(int a) {
        int* someInt = new int;

        *someInt = a;
        return someInt;
    }
    int ax = 10;
    void somethingElse(int i)
    {
        ax = i;
    }
    const int* doSomething(int a) const {
        somethingElse(a);
        return 0;
    }
};

int main() {
    test a;

    cout << *a.doSomething(12345) << endl;

    return 1;
}

This example does not compile because you are calling a const function inside a const scope. The compiler won't let you do that.

Now, I know is a test but doing this way you will never get out of the recursion, it will loop forever, and also you are leaking memory at every call by allocating on the heap, those two things together can lead to a disaster.