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.
Related
If I have a class with getters of return type both const and non-const, how can I use the non-const one?
The class (MeshManipulator.h):
namespace vortex::meshSculptEngine
{
class MeshManipulator
{
public:
...
topologyMesh::Mesh* getMesh();
const topologyMesh::Mesh* getMesh() const;
...
};
}
The code where I want to use the Mesh (SimpleMeshCorrector.cpp):
void SimpleMeshCorrector::smoothBoundaryLoops(float distance)
{
if (!_boundaryLoops.empty()) {
Mesh* mesh = getEngine()->getManipulator()->getMesh();
...
}
}
I get the following error:
A value of type "const vortex::topologyMesh::Mesh*" cannot be used to
initialize an entity of type "vortex::topologyMesh::Mesh*"
I can use const_cast but I just don't feel that this is the correct way to solve this problem.
Root cause is (as clarified in comments) that getManipulator() returns a const MeshManipulator*. On a const object, only methods declared const can be called. Thus, the const getter is always called and never the non-const version.
Depending on the context, there are three ways to go on:
Use (or write) a method that returns a mutable MeshManipulator*.
Copy the const Mesh* to a local, mutable object.
Use const_cast<Mesh*> to be able to mutate the object in place. This, however, defeats the purpose of constness. What's more, if the object pointed to was declared const this will result in undefined behavior. So use with care.
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.
I am trying to to understand const_cast.
In the example below, items_ is a private member variable.
The method getItems() is a const method, which means that it cannot modify the member variable items_.
getItems() returns a const vector reference which means that you cannot modify the member variable items_.
My question is, is const_cast necessary here? I don't think so as I don't need to cast away constness?
#include <iostream>
class test {
std::vector<Item> items_;
public:
const std::vector<Item>& getItems() const;
};
const std::vector<mv::Item>& mv::Workloads::getItems() const
{
return const_cast<std::vector<Item>&>(items_);
}
It is not only unnecessary but it is plain wrong in that place.
Consider what happens when you remove the const from the return type:
/*const*/ std::vector<mv::Item>& mv::Workloads::getItems() const
{
return const_cast<std::vector<Item>&>(items_);
}
Now the method returns a non-const reference to a const object! Note that the method itself is declared as const, hence this is const in the context of this method and also items_ is const. Using the reference returned by that method would lead to undefined behaviour when the method is called on a const test instance.
In that sense, the only effect of the const_cast here is to potentially silence an important compiler error should you ever decide to change the return type.
On the other hand, in the method as is (ie returning a const reference) there is no reason for the cast. items_ is const and a const reference to it is returned.
const_cast is useful eg to avoid code duplication for const and non-const methods when you do know for sure that the object you cast const away really is not const, see here for details.
PS: in case you actually do want to return a mutable reference to a member from a const method, you would declare the member mutable. Also then no const_cast would be required. Though, mutable should be used with care and usually isnt needed in the first place.
It is not neccessary, simply return the _items.
Const member functions see the the object itself (*this) as const, so every data member is seen as const, from which building and returning const reference is allowed.
#include <iostream>
using namespace std;
class test {
std::vector<Item> items_;
public:
const std::vector<Item>& getItems() const;
};
const std::vector<mv::Item>& mv::Workloads::getItems() const
{
return items_;
}
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.
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.