I'm new to C++. I learned that references should be used whenever possible and that pointers should be used only when strictly necessary. I also learned that const references should be used in function parameters when the function does not change the referred variable.
I understand the reasons and agree with them, but there's a common case where const references lead to confusion which is when a mutable object "becomes immutable" as an effect (const-ness) of declaring a const reference to an object. For example, the Foo class has a method named incrementX() which mutate the state of Foo when called:
class Foo {
public:
void incrementX();
private:
private int x;
}
void Foo::incrementX() {
x++;
}
class Bar {
public:
void doSomethingWith(const Foo &foo);
}
void Bar::doSomethingWith(const Foo &foo) {
foo.incrementX(); // <- illegal because incrementX() is not a const method
}
int main() {
Foo foo;
Bar bar;
bar.doSomethingWith(foo);
}
The usual solution is to declare incrementX() as a const method, which in turn forces me to declare the variable x as a mutable variable. The problem is, by turning incrementX() into a const method I'm saying that this method is not supposed to mutate the object's state, which is not true in the above example. Not only it's not true, it's also the method's intent to mutate the object's state.
I'm curious how experienced C++ programmers deal with this situation. I'm inclined to use const pointers (Foo * const foo) in such cases, would that be recommended/discourage?
Thanks.
EDIT: Just to clarify the cause of my confusion, I often hear people saying "use const refs when the function promises not to change the parameter", but what exactly "to change the parameter" means? Does it mean the function promises not to assign a new object to the parameter, or does it mean it will not mutate the objects's state? Of course, const references disallow both kind of changes, but what's the main concern when it comes to const references? Is it that it will not assign a new value to the parameter, or is it that it will not mutate the state of the object referred to by the const reference?
By taking const Foo &
void Bar::doSomethingWith(const Foo &foo)
promises not to modify the foo. Therefore it may not call it's non-const incrementX method.
If you have Bar::doSomethingWith(Foo &foo) that needs to call foo.incrementX (and therefore needs to take it's argument non-const reference), than you should reconsider whether it is really appropriate to be a method of Bar and not Foo in the first place.
Do not pass by const reference if you expect that your object will be changed, or overload the function so that you have doSomethingWith(const Foo&) and doSomethingWith(Foo&).
The whole idea is that passing by const reference forces const behaviour, so you can only invoke member functions that are marked const, and this leads to less problems in the long run.
PS: I made the doSomething a member of Foo.
Example:
#include <iostream>
using namespace std;
class Foo
{
int m=0;
public:
void doSomething(const Foo& foo) const
{
cout << "calling const reference" << endl;
}
void doSomething(Foo& foo)
{
cout << "calling reference" << endl;
foo.m++;
}
};
int main()
{
const Foo f,g ;
f.doSomething(g); // calls const reference
Foo h,k;
h.doSomething(k); // calls reference
}
Related
A co-worker asked about some code like this that originally had templates in it.
I have removed the templates, but the core question remains: why does this compile OK?
#include <iostream>
class X
{
public:
void foo() { std::cout << "Here\n"; }
};
typedef void (X::*XFUNC)() ;
class CX
{
public:
explicit CX(X& t, XFUNC xF) : object(t), F(xF) {}
void execute() const { (object.*F)(); }
private:
X& object;
XFUNC F;
};
int main(int argc, char* argv[])
{
X x;
const CX cx(x,&X::foo);
cx.execute();
return 0;
}
Given that CX is a const object, and its member function execute is const, therefore inside CX::execute the this pointer is const.
But I am able to call a non-const member function through a member function pointer.
Are member function pointers a documented hole in the const-ness of the world?
What (presumably obvious to others) issue have we missed?
The constness of execute() only affects the this pointer of the class. It makes the type of this a const T* instead of just T*. This is not a 'deep' const though - it only means the members themselves cannot be changed, but anything they point to or reference still can. Your object member already cannot be changed, because references cannot be re-seated to point to anything else. Similarly, you're not changing the F member, just dereferencing it as a member function pointer. So this is all allowed, and OK.
The fact that you make your instance of CX const doesn't change anything: again, that refers to the immediate members not being allowed to be modified, but again anything they point to still can. You can still call const member functions on const objects so no change there.
To illustrate:
class MyClass
{
public:
/* ... */
int* p;
void f() const
{
// member p becomes: int* const p
*p = 5; // not changing p itself, only the thing it points to - allowed
p = NULL; // changing content of p in const function - not allowed
}
};
In this context object is a reference to a X, not a reference to a const X. The const qualifier would be applied to the member (i.e. the reference, but references can't be const), not to the referenced object.
If you change your class definition to not using a reference:
// ...
private:
X object;
// ...
you get the error you are expecting.
The instance object of class X is not const. It is merely referenced by an object which is const. Const-ness recursively applies to subobjects, not to referenced objects.
By the alternative logic, a const method wouldn't be able to modify anything. That is called a "pure function," a concept which doesn't exist in current standard C++.
You are calling foo on object, not on this.
Since object is declared as an X&, in a constant CX, it is actually an X& const (which is not the same as const X&) allowing you to call non const methods on it.
One helpful way of thinking about it might be that your X object is not a member of CX at all.
I have a class with a header like this:
public:
const dtMeshTile* getTile(int i) const;
private:
dtMeshTile* getTile(int i);
When I try to use it like this:
const dtMeshTile* const tile = navmesh->getTile(i);
I'm getting a "'dtMeshTile* getTile(int)' is private within this context" How can I specify the public function?
Consider:
#include <cstdlib>
class Bar {};
class Foo
{
public:
Foo (Bar& bar)
:
mBar (bar)
{
}
const Bar& get() const
{
return mBar;
}
private:
Bar& get()
{
return mBar;
}
Bar& mBar;
};
int main()
{
Bar bar;
Foo foo (bar);
Bar& ref = foo.get();
}
At the point of the call: const Bar& ref = foo.get(); you might expect the const version of get() to be called, because you are assigning a const reference.
But this is not the case. Return types are not a part of a function's (or method's) signature, so when the compiler is looking for which function to call in a list of possible overloads, the return type is not considered. (In fact, the Standard rejects function overloads which differ only by return type.)
So, how does the compiler decide which function to call? By looking at the information is does have available to it. The tweo overloads are identical in terms of parameters (both are void), so the only thing it has to go on is the static type of the object used to make the call: foo. That static type in this case is Foo -- decidedly non-const.
Therefore it tried to call the only function it can: the non-const version of get(). Which of course won't compile because that is private.
In order to fox this, the static type can be changed to be a const Foo (or something similar), like this:
Foo foo (bar);
Bar& ref = foo.get();
Or maybe...
Foo foo (bar);
const Bar& ref = static_cast <const Foo&> (foo).get();
But in practice, I would rather advise that the names of these functions be unambigious, rather that relying on such "tricks" to contort the compiler in to doing what you want.
make sure navmesh is const in the context of your call. But I would not recommend const_cast it, you might read this http://www.parashift.com/c++-faq/overview-const.html .
You're hit by a pretty common design flow -- an overload set with mixed semantics.
But I guess you can't change the class, only work around it.
Your problem comes from overload resolution rules. The function is selected based on arguments. Only. private/public stuff is ignored at this stage. The selection happens based on the type before -> if if it's const T*, the first function is selected, for T* the second.
Assess check is applied then, so for the latter case you get the error report. To force the desired function you must use a cast, or better create a free wrapper function
const dtMeshTile* getXXXTile(const XXX* p, int i) {return p->getTitle(i);}
(or a ref-taking variant).
In my codebase the second function would have a different name, as obtaining a mutable string is way different in semantics.
I've got a const method in my class, which cannot be changed to non-const. In this method, I need to call a non-const method but the compiler doesn't let me do that.
Is there any way around it? Here is a simplified sample of my code:
int SomeClass::someMethod() const {
QColor saveColor = color();
setColor(QColor(255,255,255)); // Calling non-const method
// ....
setColor(saveColor); // restore color
return 1;
}
You could use const_cast on this pointer,
int SomeClass::someMethod() const {
const_cast<SomeClass*>( this )->setColor(...);// Calling non-const method
//whatever
}
but if you do that for an object that was originally declared const you run into undefined behavior.
So this:
SomeClass object;
object.someMethod();
is okay, but this:
const SomeClass object;
object.someMethod();
yields undefined behavior.
The real solution is that your const function should not be const in the first place.
One of the challenges of doing const-correctness is you can't do it halfway. It's either all or nothing. If you try to do it halfway, you end up in a tough spot like you are here. You end up with a nice const-correct class being used by some crazy old, typically legacy (or written by an old curmudgeon) code that isn't const-correct and it just doesn't work. You're left wondering if const-correctness is worth all the trouble.
I need to call a non-const method [from a const method]
You can't -- not directly. Nor should you. However, there is an alternative...
Obviously you can't call a non-const method from a const method. Otherwise, const would have no meaning when applied to member functions.
A const member function can change member variables marked mutable, but you've indicated that this is not possible in your case.
You could attempt to cast away constness by doing something like SomeClass* me = const_cast<SomeClass*>(this); but A) This will typically result in UB, or 2) It violates the whole idea of const-correctness.
One thing you could do, if what you're really trying to accomplish would support this, is to create a non-const proxy object, and do nonconst-y stuff with that. To wit:
#include <iostream>
#include <string>
using namespace std;
class Gizmo
{
public:
Gizmo() : n_(42) {};
void Foo() const;
void Bar() { cout << "Bar() : " << n_ << "\n"; }
void SetN(int n) { n_ = n; };
int GetN() const { return n_; }
private:
int n_;
};
void Gizmo::Foo() const
{
// we want to do non-const'y things, so create a proxy...
Gizmo proxy(*this);
int save_n = proxy.GetN();
proxy.SetN(save_n + 1);
proxy.Bar();
proxy.SetN(save_n);
}
int main()
{
Gizmo gizmo;
gizmo.Foo();
}
If you require to change some internal state inside a const-method you can also declare the affected state mutable:
class Foo {
public:
void doStuff() const { bar = 5; }
private:
mutable int bar;
};
This is intended for cases where you have stuff like mutexes as members of your class. Acquiring and releasing a mutex does not affect client-visible state, but is technically forbidden in a const-method. The solution is to mark the mutex mutable. Your case looks similar, although I think your class requires some refactoring for this solution to be applicable.
Also, you might want to read this answer to see how you can make this temporary state-change exception-safe using RAII.
How to call a non-const method from a const method?
You should not. You might run into undefined behaviour if you cast away the const-ness of this, using const_cast. The usage ofconst_cast will shut the compiler's mouth up, but that isn't a solution. If you need to do, then it means the const function should not be const in the first place. Make it non-const.
Or, you should do something else, which would not require you to call non-const function from const function. Like, don't call setColor function? Like, split the const function into more than one functions (if you can do that)? Or something else?
In your particular case, if setColor only sets some member variable, say m_color, then you can declare it mutable:
mutable QColor m_color;
and then set it in your const function, without calling setColor function, and without doing const_cast.
A co-worker asked about some code like this that originally had templates in it.
I have removed the templates, but the core question remains: why does this compile OK?
#include <iostream>
class X
{
public:
void foo() { std::cout << "Here\n"; }
};
typedef void (X::*XFUNC)() ;
class CX
{
public:
explicit CX(X& t, XFUNC xF) : object(t), F(xF) {}
void execute() const { (object.*F)(); }
private:
X& object;
XFUNC F;
};
int main(int argc, char* argv[])
{
X x;
const CX cx(x,&X::foo);
cx.execute();
return 0;
}
Given that CX is a const object, and its member function execute is const, therefore inside CX::execute the this pointer is const.
But I am able to call a non-const member function through a member function pointer.
Are member function pointers a documented hole in the const-ness of the world?
What (presumably obvious to others) issue have we missed?
The constness of execute() only affects the this pointer of the class. It makes the type of this a const T* instead of just T*. This is not a 'deep' const though - it only means the members themselves cannot be changed, but anything they point to or reference still can. Your object member already cannot be changed, because references cannot be re-seated to point to anything else. Similarly, you're not changing the F member, just dereferencing it as a member function pointer. So this is all allowed, and OK.
The fact that you make your instance of CX const doesn't change anything: again, that refers to the immediate members not being allowed to be modified, but again anything they point to still can. You can still call const member functions on const objects so no change there.
To illustrate:
class MyClass
{
public:
/* ... */
int* p;
void f() const
{
// member p becomes: int* const p
*p = 5; // not changing p itself, only the thing it points to - allowed
p = NULL; // changing content of p in const function - not allowed
}
};
In this context object is a reference to a X, not a reference to a const X. The const qualifier would be applied to the member (i.e. the reference, but references can't be const), not to the referenced object.
If you change your class definition to not using a reference:
// ...
private:
X object;
// ...
you get the error you are expecting.
The instance object of class X is not const. It is merely referenced by an object which is const. Const-ness recursively applies to subobjects, not to referenced objects.
By the alternative logic, a const method wouldn't be able to modify anything. That is called a "pure function," a concept which doesn't exist in current standard C++.
You are calling foo on object, not on this.
Since object is declared as an X&, in a constant CX, it is actually an X& const (which is not the same as const X&) allowing you to call non const methods on it.
One helpful way of thinking about it might be that your X object is not a member of CX at all.
class Foo {
protected:
QPoint& bar() const;
private:
QPoint m_bar;
};
QPoint& Foo::bar() const {
return m_bar;
}
I got this error:
error: invalid initialization of reference of type ‘QPoint&’ from expression of type ‘const QPoint’
However it works if I change it to this:
QPoint& Foo::bar() const {
return (QPoint&) m_bar;
}
1) I don't understand why the compiler says that my QPoint is const.
2) Is it ok to leave the cast there?
In a non-const member function of class Foo the this pointer is of the type Foo* const - that is, the pointer is const, but not the instance it points to. In a const member function, however, the this pointer is of the type const Foo* const. This means that the object it points to is constant, too.
Therefore, in your example, when you use this->m_bar (of which m_bar is just the short form), then m_bar is a member of a constant object - which is why you cannot return it as a non-const reference.
This actually makes sense from a design POV: If that Foo object is a constant object, and you are allowed to invoke Foo::bar for constant objects, then, if this would return a non-const reference to some internals which you can fiddle with, you would be able to change the state of a constant object.
Now you have to look at your design and ask yourself how you arrived at this point and what your actual intention is. If that m_bar member isn't really part of the state of the object (for example, it's only there for debugging purposes), then you could consider making it mutable. If it is part of the state of the object, then you have to ask yourself why you want to return a non-const reference to some internal data of a constant object. Either make the member function non-const, or return a const reference, or overload the member function:
class Foo {
public:
const QPoint& bar() const {return m_bar;}
QPoint& bar() {return m_bar;}
// ...
};
What you're trying to do is a no-no. You do not want to return a QPoint & from your bar function as this breaks encapsulation because a caller can now modify m_bar out from underneath QPoint. (luckily you have the function declared as const or you wouldn't get an error here and you would still be breaking encapsulation).
What you want in this case is
const QPoint &Foo::bar() const
{
return m_bar;
}
Edit based on user comment:
IMHO, this would be better solved by adding a setX to Foo instead of calling a non-const function from a non-const reference returned by an accessor function that should really be const. Overloading the accessor function to remove the const just puts a band-aid over the real problem and just hides the fact that encapsulation is compromised. Adding setX to Foo fixes the encapsulation problem and also plugs the leaking interface you are creating by returning a non-const reference to private data.
For example, if you put foo.bar().setX(100); in many parts of your application and later change the type of QPoint to one that doesn't implement setX or simply rename the function setX to say setPointX you have problems b/c you now have to go around a rename/refactor all of these calls. Creating a setX on Foo makes the code easier to call foo.setX(100) vs foo.bar().setX(100), is const correct, and encapsulates your data. If you changed QPoint to be just 2 x and y coordinates in Foo, nothing outside of your class would have to change b/c you have good encapsulation.
The const on the function tells the compiler that the function doesnt modify any member variables. However, since your returning a reference to the member variable it cant guarantee that any more and thus has the compile error.
The compiler is not expecting your member variable to be const but the return from the function to be const. Remove the const from the function def.
either use
const QPoint& Foo::bar() const {
return m_bar;
}
or
QPoint& Foo::bar() {
return m_bar;
}
I guess you could also declare m_bar as:
mutable QPoint m_bar;
EDIT: mutable defense
#tstenner:
mutable has its place. It is not 'evil' definitely no more so than void* or casting. Assume something like the following:
class foo {
SomeType bar;
public:
foo() : bar() { }
const SomeType& bar() const { return a; }
};
In this case, bar is ALWAYS constructed, even if bar() is never called. This may be fine, but if SomeType has a costly constructor, it can be preferable to allow lazy instantiation of bar.
Consider:
class foo2 {
mutable SomeType* bar;
mutable bool cached;
public:
foo2() : bar(0), cached(false) { }
const SomeType& bar() const {
if( ! cached ) {
cached = true;
bar = new SomeType();
}
return *bar;
}
};
This allows foo2 to mimic a non-lazy instantiated class, while being lazily instantiated. Granted, the mutability of foo2 has implications for thread safety, but these can be overcome with locking if needed.
If it allowed you to return a reference to the variable, then you could modify a const instance of Foo class. Consider such code:
void baz(const Foo &foo)
{
QPoint &ref = foo.bar(); //if it was allowed...
ref = 5; // ...you could have modified a const object foo!
}
Therefore compiler prevents you from doing that.
You should either declare your method returning const QPoint& or to revise your understanding of what really const is for.
Someone may advise you to use mutable. Don't. mutable keyword is to allow implementation of the class to modify internal member variables of const objects (for example, for memoization purposes), rather than to expose non-const variable (!) to external code.