Calling a const function rather than its non-const version - c++

I tried to wrap something similar to Qt's shared data pointers for my purposes, and upon testing I found out that when the const function should be called, its non-const version was chosen instead.
I'm compiling with C++0x options, and here is a minimal code:
struct Data {
int x() const {
return 1;
}
};
template <class T>
struct container
{
container() {
ptr = new T();
}
T & operator*() {
puts("non const data ptr");
return *ptr;
}
T * operator->() {
puts("non const data ptr");
return ptr;
}
const T & operator*() const {
puts("const data ptr");
return *ptr;
}
const T * operator->() const {
puts("const data ptr");
return ptr;
}
T* ptr;
};
typedef container<Data> testType;
void testing() {
testType test;
test->x();
}
As you can see, Data.x is a const function, so the operator -> called should be the const one. And when I comment out the non-const one, it compiles without errors, so it's possible. Yet my terminal prints:
"non const data ptr"
Is it a GCC bug (I have 4.5.2), or is there something I'm missing?

If you have two overloads that differ only in their const-ness, then the compiler resolves the call based on whether *this is const or not. In your example code, test is not const, so the non-const overload is called.
If you did this:
testType test;
const testType &test2 = test;
test2->x();
you should see that the other overload gets called, because test2 is const.

test is a non-const object, so the compiler finds the best match: The non-const version. You can apply constness with static_cast though: static_cast<const testType&>(test)->x();
EDIT: As an aside, as you suspected 99.9% of the time you think you've found a compiler bug you should revisit your code as there's probably some weird quirk and the compiler is in fact following the standard.

It doesn't matter whether Data::x is a constant function or not. The operator being called belongs to container<Data> class and not Data class, and its instance is not constant, so non-constant operator is called. If there was only constant operator available or the instance of the class was constant itself, then constant operator would have been called.

But testType is not a const object.
Thus it will call the non const version of its members.
If the methods have exactly the same parameters it has to make a choice on which version to call (so it uses the this parameter (the hidden one)). In this case this is not const so you get the non-const method.
testType const test2;
test2->x(); // This will call the const version
This does not affect the call to x() as you can call a const method on a non const object.

Related

Allowing a function to mutate a const object's member variable

This is related to the (currently) closed question I asked earlier: Can you mutate an object of custom type when it's declared as constant?
Suppose we have something that looks like the following:
class test
{
public:
test() : i{4}, ptr{&i} {};
int i;
int *ptr;
int *get_ptr() const {return ptr;}
};
void func(const test &t, int j) {
*(t.get_ptr()) = j;
// auto ptr = t.get_ptr();
// *ptr = j;
}
int main(int argc, char const *argv[])
{
test t;
std::cout << t.i << std::endl;
func(t, 5);
std::cout << t.i << std::endl;
}
We have this func that takes in a const test &. When I see this signature (and if I didn't look at the implementation of the function), it makes me want to assume that nothing in t will get modified; however, the member variable i is able to be modified through the ptr member variable, as we see here.
I don't usually write code that end up working this way, so I'm wondering if code like this is discouraged?
Furthermore, is it reasonable to assume (most of the time) that an object declared as const will not be mutated?
Yes code like this is definitely discouraged. It completely ignores the reason we have the const keyword in the first place. The function is deliberately modifying something that it is advertising it will not modify
That means that whoever wrote the get_ptr() function messed up because they declared it const but let it return a pointer to non-const object (so one that can be changed, defeating the purpose of declaring the function const)
If whatever get_ptr() returns could properly be modified by such a function then it should be an implementation detail, a private (or protected) variable marked with the mutable keyword.
test::get_ptr() should have two overloads.
const int* get_ptr() const { return ptr; }
int* get_ptr() { return ptr; }
If func() wants to change the test object given to it then it should take test&, not const test&
The key is here:
int *get_ptr() const {return ptr;}
You define get_ptr as const which is akin to saying "get_ptr is not going to change any attributes of the class". And it doesn't. It returns the value of the attribute ptr, which is a int*, and points to a mutable instance of an int which happens to be an attribute of the class as well.
The compiler has no way of knowing this, so from the compiler's perspective the promise was kept. However in reality you're circumventing the const qualifier and allowing to mutate an otherwise immutable attribute.
Not the best of coding practices, but whoever writes such code should, obviously, not expect for i to remain as it was set in the class methods if get_ptr is ever called.

How to define const getters that trigger a calculation?

I have a class which contains a data member that occasionally needs to be recalculated, though it is likely to be accessed multiple times before a recalculation is needed.
I have defined both const and non-const getter methods for the data, and within the getter method I would like to check whether or not the calculation needs to be run, and call the appropriate method if it does.
In the non-const getter, I check whether the value is up-to-date, and if not run the calculation before returning the data. Doing the same in the const getter caused the compiler to complain about the this object being a const type while the calculation method is non-const. I was therefore surprised that the code compiles if I simply call the non-const getter within the const getter. Could someone please explain why this works, because I am slightly confused.
class A {
bool isUpToDate=false;
double someData=0;
// Do some calculation
void calcData()
{
someData = doSomeCalc();
isUpToDate = true; // data is now up-to-date
}
// non-const getter
double& data()
{
if(!isUpToDate)
{
// run the calculation only if data is not up-to-date
calcData()
}
return someData;
}
// const getter that doesn't work
const double& data() const
{
if(!isUpToDate)
{
calcData() // compiler error: "this object is type const A but
calcData is non-const"
}
return someData;
}
// const getter that (mysteriously) works
const double& data() const
{
return data(); // why doesn't the compiler complain that data() is non-const?
}
I am sure that this behavior is actually reasonable and well-defined, I am just curious why it works because I don't understand what is happening here. I am using g++ as my compiler with the c++11 standard, in case that is a relevant factor in why this works.
You're not calling the non-const getter; you're calling yourself:
const double& data() const
{
return data();
}
is infinite recursion.
Because of data() const, *this is effectively const within the method. The call data() is equivalent to this->data(). Because this is a const A *, this selects the const getter again.
I was therefore surprised that the code compiles
Sure it compiles, but it doesn't actually work. It will either go into an infinite loop and hang or just crash.
In this scenario, you can declare someData and isUpToDate as being mutable. That means they can be modified even from a const member function. Then make calcData() be const, so that it can be called from another const member function.
Such an approach will often be eyed with suspicion! I use it for mutexes and for caches. I worry that yours might be perhaps slightly too much for this.
Do you really need data() to be const? You should make sureā€¦
Make that field mutable, and use an update function:
bool updateNeeded;
double getNewValue();
class MyResource {
mutable double someData = 0.0;
void update() const {
// Because someData is mutable, this works fine
if(updateNeeded()) {
someData = getNewValue();
}
}
public:
double& getData() {
update();
return someData;
}
double const& getData() const {
update();
return someData;
}
};
When you have a member function like const double& data() const, all functions called by data must also be const, and not modify the object. For those that stumble onto this: Meaning of 'const' last in a function declaration of a class?
There are some ways to solve this:
You can change void calcData() to void calcData() const this will tell the compiler that the calculation method is const. This won't work here because your are assigning the result so it is non-const (it modifies member variables) so the compiler will yell at you.
You can change double const& getData() const to double const& getData(). But this will not work if you need A to be const sometimes.
Another solution is
class A {
bool isUpToDate=false;
double someData=0;
double& data()
{
if(!isUpToDate)
{
// run the calculation only if data is not up-to-date
someData = doSomeCalc();
isUpToDate = true;
}
return someData;
}
double data() const // Don't change anything, just return by value
{
if(!isUpToDate)
{
return doSomeCalc();
}
return someData;
}
}
This will return by value and re-calculate everything. The disadvantage is that it may be bad performance-wise if doSomeCalc() is intensive, since it needs to call it every time and cannot update someData.
Other answers have already mentioned using the mutable qualifier for someData (and isUpToDate). This will work fine, but some may be averse to using the mutable keyword, as they are usually used for specific purposes and can be dangerous if handled poorly.

'this' argument to member function 'select' has type 'const SelectParam', but function is not marked const

I'm trying to call a function on a polymorphic item. But I get the following error message at compile time:
'this' argument to member function 'select' has type 'const SelectParam', but function is not marked const
the error is shown at the p->selection(*it)
std::set<Tuple>::iterator it;
for (it = tuples.begin(); it != tuples.end();) {
for (const SelectParam* p: selectionParams) {
bool successful = p->select(*it);
if( !successful ) {
it = tuples.erase(it);
} else {
it++;
}
}
}
and here's how those classes are defined. (I use to not have all the const and & is there but I put them everywhere I could in hopes that I would make whatever it wanted const but clearly I'm not approaching the problem right since it's not changing anything.
In one of the child classes that is being stored at parent pointer.
bool const select(Tuple const & tup) {
bool matched = false;
if (tup[idx] == val) {
matched = true;
}
return matched;
}
In the other child class that is being used with polymorphism
bool const select(Tuple const & tup) {
bool matched = false;
if (tup[idx1] == tup[idx2]) {
matched = true;
}
return matched;
}
And finally here's the parent class that's super simple.
class SelectParam {
public:
virtual const bool select( Tuple const & t) = 0;
};
Thanks in advance for being willing to help my feeble brain.
Indeed, you cannot call a non-const method a const object. But you also cannot call a non-const method through a pointer or reference to a const object (regardless of whether the referred-to object is const or not).
This means that this:
const SelectParam* ptr = whatever();
ptr->select(someTuple);
is ill-formed.
In your case, you've declared a pointer to a const SelectParam here on this line:
for (const SelectParam* p: selectionParams) {
Simply remove the const and it should work :-)
On the other hand, if select is never meant to modify the object, simply mark it as const:
virtual const bool select( Tuple const & t) const = 0;
And your code should also work.
You need to explicitly tell the compiler that your function will not modify any members:
bool const select(Tuple const & tup) const {
An object declared as const can neither be changed by a const nor a non-const member function (except for constructor and destructor). Even if it is passed by reference. There are two exceptions to this rule:
The constness can be casted away (casting the const away) but is generally not advised.
Class members can be declared using the mutable keyword. These members can be changed through member functions even if the containing object is declared const.
More can be read here:
const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.
As commented by others, one solution would be to add the const keyword to the member function in both its declaration and definition. With that, the function can be called even on const objects.
What is up with this though?
Within a member function, this is a pointer to the current object the function was called on [see].

Returning const reference from a member get method

typedef vector<int> intvec;
class MyClass
{
intvec m_member;
public:
const intvec& GetVec();
};
const intvec& MyClass::GetVec()
{
return m_member;
}
int main(int argc, char *argv[])
{
MyClass myClassObj;
myClassObj.GetVec().push_back(11); //This doesn't work with const reference
myClassObj.GetVec().push_back(22); //This doesn't work with const reference
for(intvec::const_iterator iter = myClassObj.GetVec().begin(); iter != myClassObj.GetVec().end(); ++iter)
{
cout << *iter << ", " ;
}
cout << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
If the return type of GetVec() is non const reference then myClassObj.GetVec().push_back(11); works, but for const reference return this doesn't work (compilation error). I understand that if the GetVec() method itself was const i.e. const intvec& GetVec() const;, then myClassObj.GetVec().push_back(11); wouldn't work because that would mean modifying the "this" pointer.
You can overload the function on it's const qualification:
const intvec& GetVec() const; // Can access, but not modify, a const object
intvec& GetVec(); // Can access or modify a non-const object
Or you could just make the data member public and have exactly the same restrictions. There's little point in accessor functions unless they're used to restrict access or maintain class invariants, which these don't.
It is expected that a modifying function like push_back cannot be used on a const reference. Assuming that push_back is something that appends an item to an array, that constitutes a modification to the object, so if the object is constant then you can't do it.
I understand that if the GetVec() method itself was const i.e. const
intvec& GetVec() const;, then myClassObj.GetVec().push_back(11);
wouldn't work because that would mean modifying the "this" pointer
This is correct. And a getter function should have the const which prevents you from modifying "this".
const intvec& MyClass::GetVec() const { return m_member; }
A getter function is usually used to read data. Your class (the owner of m_member) should be the one to modify that member if needed. If you can modify the member from outside the class, one looses control of who by and when m_member is being changed (making debugging a difficult process and reducing the readability for developpers).
If you want to change m_member, you would typically add a method to your class to do so.
If the return type of GetVec() is non const reference then
myClassObj.GetVec().push_back(11); works, but for const reference
return this doesn't work (compilation error).
You simply cannot push an element on a const vector, because then it wouldn't be a const vector :). I think you are somewhat confused about the const keyword.
const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.

C++ const in getter

I'm still learning about C++ and I'm reading everywhere that I have to use const everywhere I can (for speed reason I think).
I'm usually write my getter method like this:
const bool isReady() {
return ready;
}
But I've seen that some IDE autogenerate getter in this way:
bool getReady() const {
return ready;
}
But, writing delegates, it happened to me to find this error if the const is after the function:
member function 'isReady' not viable: 'this' argument has type 'const VideoReader', but function is not marked const
So that, what is the better way to write a const getter? Do I really have to care about?
There is a huge difference between the two ways.
const bool isReady()
The code above will return a const bool, but it does not guarantee that the object will not change its logic state.
bool isReady() const
This will return a bool, and it guarantees that the logic state of your object will not change. In this case it is not necessary to write const in front of the return type. It makes no sense to return a const bool because it is a copy anyway. So making it const is useless. The second const is needed for const correctness, which is not used for speed reasons but to make your program more reliable and safe.
They mean two differnt things:
const bool isReady() {
return ready;
}
This returns a constant bool. Meaning a bool which cannot change value from the time it's been created.
bool getReady() const {
return ready;
}
This is a a constant function, meaning a function that will not alter any member variables of the class it belongs to. This is the style recommended to use for getters, since their only purpose is to retrieve data and should not modify anything in the process.
const method informs compiler that you will not modify class instance on which this method is called:
class A {
public:
bool getReady() const {
return ready;
}
};
so if you try to modify your object inside getReady() then compiler will issue error. Const methods are usefull where you have ie.: const A&, or const A*, then you can call only const methods on such objects.
as for:
const bool isReady() {
return ready;
}
this const provides actually no real benefit, because bool is copied while isReady() returns. Such const whould make sense if returned type was a const char* or const A&, in such cases const makes your char string or A class instance immutable.
A const getter has the signature
bool getReady() const
The other version isn't a const method, it just returns a const value (which is basically useless).
Having a const getter allows you to call it on const objects:
const Object obj;
obj.getReady();
This is only valid if getReady is marked as const.
There is a difference between using the const keyword for the return type or for the method signature. In the first case the returned value will be a constant value. In the second case the method will be a so-called constant method, which cannot change the representation of the object. On constant objects, only the constant methods are callable.