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;
}
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 theconst
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; }
};