Why Do We Need const methods? - c++

class function const is used to tell the compiler that a class function will not change a member variable. Thus, a constant object of that type can safely call it. Below is a simple example.
#include <iostream>
using namespace std;
class X {
private:
int a{1};
public:
void PrintA() const {
cout << a << "\n";
}
};
int main() {
const X x;
x.PrintA();
}
We tell the compiler that #PrintA is const, so constant objects can safely call it. However, it seems that the compiler is actually smart enough to detect that a function is read-only or not, independent of the const keyword. If I add an a=10 in the above code like so
#include <iostream>
using namespace std;
class X {
private:
int a{1};
public:
void PrintA() const {
cout << a << "\n";
a = 10;
}
};
int main() {
const X x;
x.PrintA();
}
I get
exp.cpp: In member function ‘void X::PrintA() const’:
exp.cpp:11:9: error: assignment of member ‘X::a’ in read-only object
a = 10;
In other words, the const key-word can't trick the compiler into allowing the mutation of a constant object. So my question is, why do developers need to declare a method const? It seems like, even without that hint, the compiler distinguishes read-only and non-read-only methods, so can properly catch cases of attempts to mutate constant objects.

It's not a hint -- it's part of the interface of the method. If you remove the const, the error in PrintA will go away and you'll get an error in main instead. You need const for the same reason you need public and private -- to define the interface you want. The compiler will then check to make sure you don't violate that interface you've declared.

the compiler distinguishes read-only and non-read-only methods
First consider how easily the compiler can do this with the const designation as it exists today.
To determine if the implementation of PrintA obeys the rules, the compiler only needs to look at that implementation.
To determine if x.PrintA(); is valid for const X x; it only needs the declaration of PrintA.
Now imagine if we didn't have function-level const
To determine if the implementation of PrintA obeys the rules, the compiler has to determine if it's not acting read-only and then scan across your entire program to find if it ever gets called on a const object.
I'm sure that would massively bloat the link time of large programs.
But then a significant concern are virtual functions. Imagine one derived class overrides with a read-only implementation, but then a different derived class overrides with a non-read-only implementation. Then if such a method is called on a const object, what is the compiler to do since it may not be able to determine at compile-time which implementation is going to be called? Would we just have to rule out virtuals from ever being possible to call on const objects? That would be unfortunately limiting.
Furthermore, this idea wouldn't work when callers vs implementations are separated across DLL boundaries (even for non-virtual functions), since those are only connected together at run-time.
So overall it just seems more difficult/problematic for us the have the ability to declare const objects if we were to leave it to the compiler to have to figure out if methods are implemented in a const way or not.

Related

Reference return for setter

A. How useful/cumbersome is the following trick of using the same function for getter as well as setter, by returning a reference?
B. How good is the practice of adding const to the end of function declarations in case of getters and setters?
#include <iostream>
class A
{
int varReadWrite_;
int varReadOnly_;
int varRestricted_;
public:
A() : varReadOnly_(25) {}
virtual ~A() {}
int& varReadWrite() { return varReadWrite_; }
int varReadOnly() { return varReadOnly_; }
int varRestricted() { return varRestricted_; }
void setVarRestricted(int i); //throwable
};
int main(int argc, char *argv[])
{
A a;
a.varReadWrite() = 45;
std::cout << a.varReadOnly() << a.varReadWrite() << std::endl;
return 0;
}
The reasons, why I chose this design was:
ease of access of explicitly read-only or explicitly writable variables.
the restricted (I dont know what else to call them), the variables, that require sanitization and filtering before being assigned -- these variables might require an explicit setter.
Using boost fusion map is also an interesting possibility as shown here
Update
Const Reference Members are interesting for read-only access to variables, e.g.
class A {
int mA;
public:
int& a;
A(int a_ = 0) : mA(a_), a(mA) {}
};
Practically this comes with the extra effort to code the copy and move constructors, which is an acceptable compromise for me.
Cpp Reference Copy Construtor says
The implicitly-declared or defaulted copy constructor for class T is defined as deleted if... T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors);
A. How useful/cumbersome is the following trick of using the same function for getter as well as setter, by returning a reference?
Returning a reference to your internal members in general is not recommended since this way you give an easy access to others so they could change your object internal state without using any method provided by the object's class API. Thus, it will be very difficult to track this kind of changes in the code. In general changes in the internal state of an object should only be possible through methods that belongs to the class API.
B. How good is the practice of adding const to the end of function declarations in case of getters and setters?
if you refer to adding const for methods like:
void PrintState() const
Then in general this doesn't make sense for setters. Const in this case means This method doesn't change the object state. So it's a commitment that you give to the caller to say: I will not change the object state by this call. In general it's very good practice since it helps you during the design to think about your methods and see which one is really modifying the object state or not. Additionally, it's a defensive programming since
it's recursive: if you pass this object to some method by reference (through a pointer or reference) he can't call const methods unless this method is marked as const also. So this prevents from changing the object state by error.
Accessors (a.k.a getters and setters) are as good/cumbersome as having public member variables, as you've just violated encapsulation and lied yourself. Mixing them in a single function is even worse, as the caller may hold the returned reference, opening the hole for even more subtle bugs than described in the link above.
Secondly, adding const to a member function declaration will protect you from setters, but not from getters. Anyway, plan your designs better off :).

Does changing a method to add the hidden this pointer break binary compatibility?

Example code :
// Base.hpp
class Base
{
public:
void changeInternals();
int readInternals();
void printString(std::string& iString);
private:
int m_Internal;
};
// Base.cpp
void Base::changeInternals()
{
m_InternalValue = 5;
}
int Base::readInternals()
{
return m_InternalValue;
}
void Base::printString(std::string& iString)
{
std::cout << iString << std::endl;
}
My understanding is that, under optimisation with g++, the first two member functions (changeInternal and readInternal) will have the 'this' pointer as part of the function arguments, so it can access the member variable m_Internal. However, the third member function, printString, doesn't need to view the member variable and as such won't have the this pointer in the arguments?
In that case, if we changed thus:
void Base::printString(std::string& iString)
{
std::cout << boost::lexical_cast<std::string>(m_Internal) << std::endl;
}
The member function would now require access to m_Internal, and would therefore require the caller of this function to put the value of the 'this' pointer into the register.
I would expect this to break binary compatability, but I cannot seem to find this in any list of "binary-compatability gotchas". Is there a requirement that all member functions, regardless of touching the internals or not, have the this pointer? Examining gdb output in cores (I can't copy/paste here sadly :(, sorry) implies not.
For the purpose of this question, please assume that inlining is not taking place here (through GCC never_inline attributes)
A member function is ALWAYS[1] called with the this pointer, whether it is used or not. This is so that the compiler doesn't have to "know" whether some function uses the this pointer or not. Consider the case where the function is included only as a declaration in a header file, and the actual implementation is compiled separately in a different source file - how would the compiler know? Or in the case where the function is virtual, and there are multiple possible classes, some of which use, and some of which don't use this (implicitly) inside the member function.
This does not apply to static member functions - that's part of the point of static member functions.
[1] Of course, in the case where the compiler can "see" the source code of the function, it may choose to inline the actual function, and if the this pointer is not being used, it can then be removed as part of the inlining process. But this is again not a break in compatibility.

Why doesn't C++ cast to const when a const method is public and the non-const one is protected?

I created a class with two get methods, one const and one non-const. The const method is public, so users can query the vector. The non-const method is protected, so I can use it to modify the data I need.
When I try to use the class, however, and call the get method, the compiler complains that the non-const method is protected. Instead, I have to use const_cast to cast the object to const, so I can get instead the public method.
Is there a way to solve this? Why wouldn't the compiler do the cast itself, since there is a public method? If I remove the protected version and just leave the const one, it works fine, so it does do the cast in this situation. Casting to const is always safe. It's removing constness that is a problem.
Member access control is the very last thing that occurs when calling a member function. It happens after name lookup, template argument deduction, overload resolution, and so on. The reason why it is done last is because it was decided that changing the access control for a member should not suddenly change the execution of client code.
Imagine access was checked before overload resolution, and you used a library and a certain member function in that library. Then the library authors made the function private. Suddenly, your code starts using a different overload and behaves in a completely different way. The library authors probably intended that anybody using that overload of the function should stop using it, but they didn't intend to change everybody's code. However, as the standard is actually defined, your code would now start giving you an error for using a private member, rather than behave differently.
The solution is to simply change the name of your protected member function so that it isn't considered.
The compiler considers accessibility after it decides what member function it wants to call. That is, protected and private functions are still visible, even though they aren't accessible.
Why? One reason is that if you made inaccessible functions ignored by overload resolution, you could change what function is called simply by changing its accessibility. With the current rules, you can only cause compiling code to fail to compile, or cause code that currently doesn't work to compile, or change something with no effect on the meaning of the code. You cannot change access specifiers and silently cause a different function to be called.
As a contrived example, here's a pretty terrible class interface:
public:
// Returns the amount of change tendered for this transaction.
MoneyAmount change() const;
private:
// Account for a change of currency. Charges standard moneychanger's fee.
MoneyAmount change(Currency toCurrency = Currency::USD);
If inaccessible functions were removed from overload resolution, client code could call change() just fine. And if later the second change(Currency) function was made public and the first one deleted, that code would suddenly silently call another function with an entirely different purpose. The current rules prevent a change of access specifier from changing the behavior of a compiling program.
In C++, method selection (overloading resolution) happens before considering public/private access control.
Use a protected setter method instead (or data member) instead of the non const getter method.
It makes no difference if you have s.th. like
class A {
SomeType foo_;
protected:
SomeType& foo() { return foo_; }
public:
const SomeType& foo() const { return foo_; }
};
or
class A {
protected:
SomeType foo_;
public:
const SomeType& foo() const { return foo_; }
};
That is the nature behavior of C++, if the caller code the object of the class is non-const so the non-conversion, which is defined as protected one. You need defined the object of class as const or use const-cast on the object of the class, which will result that the const version of the method will be called.
#include <iostream>
class Foo {
public:
const void bar() const { std::cout << " const version called\n";}
protected:
void bar() { std::cout << " non const version called\n";}
};
int main(int argc, char** argv)
{
const Foo c;
c.bar(); // -> work
Foo c1;
c1.bar(); // compiler complain -> void Foo::bar() is protected
const_cast<const Foo&>(c1).bar(); // fine
}

Using 'const' in class's functions [duplicate]

This question already has answers here:
Meaning of 'const' last in a function declaration of a class?
(12 answers)
Closed 5 years ago.
I've seen a lot of uses of the const keyword put after functions in classes, so i wanted to know what was it about. I read up smth at here: http://duramecho.com/ComputerInformation/WhyHowCppConst.html .
It says that const is used because the function "can attempt to alter any member variables in the object" . If this is true, then should it be used everywhere, because i don't want ANY of the member variables to be altered or changed in any way.
class Class2
{ void Method1() const;
int MemberVariable1;}
So, what is the real definition and use of const ?
A const method can be called on a const object:
class CL2
{
public:
void const_method() const;
void method();
private:
int x;
};
const CL2 co;
CL2 o;
co.const_method(); // legal
co.method(); // illegal, can't call regular method on const object
o.const_method(); // legal, can call const method on a regulard object
o.method(); // legal
Furthermore, it also tells the compiler that the const method should not be changing the state of the object and will catch those problems:
void CL2::const_method() const
{
x = 3; // illegal, can't modify a member in a const object
}
There is an exception to the above rule by using the mutable modifier, but you should first get good at const correctness before you venture into that territory.
Others have answered the technical side of your question about const member functions, but there is a bigger picture here -- and that is the idea of const correctness.
Long story short, const correctness is about clarifying and enforcing the semantics of your code. Take a simple example. Look at this function declaration:
bool DoTheThing(char* message);
Suppose someone else wrote this function and you need to call it. Do you know what DoTheThing() does to your char buffer? Maybe it just logs the message to a file, or maybe it changes the string. You can't tell what the semantics of the call are by just looking at the function declaration. If the function doesn't modify the string, then the declaration is const incorrect.
There's practical value to making your functions const correct, too. Namely, depending on the context of the call, you might not be able to call const-incorrect functions without some trickery. For example, assume that you know that DoTheThing() doesn't modify the contents of the string passed to it, and you have this code:
void MyFunction()
{
std::string msg = "Hello, const correctness";
DoTheThing(msg.c_str());
}
The above code won't compile because msg.c_str() returns a const char*. In order to get this code to compile, you would have to do something like this:
void MyFunction()
{
std::string msg = "Hello, const correctness";
DoTheThing(msg.begin());
}
...or even worse:
void MyFunction()
{
std::string msg = "Hello, const correctness";
DoTheThing(const_cast<char*>(msg.c_str()));
}
neither of which, arguably, are 'better' than the original code. But because DoTheThing() was written in a const-incorrect way, you have to bend your code around it.
The meaning is that you guarantee to clients calling a const function member that the state of the object will not change. So when you say a member function is const it means that you do not change any of the objects member variables during the function call.
const, when attached to a non-static class method, tells the compiler that your function doesn't modify the internal state of the object.
This is useful in two ways:
If you do write code that changes internal state in your const method, the compiler catches the error, moving a programming error from run-time to compile-time.
If client code calls a non-const method on a constant pointer, the compiler catches the error, ensuring the "chain of not changing things" is maintained.
Typically you want to declare all non-mutating non-static class methods as const. This allows calling code to use the const qualifier on pointers, and it helps catch mistakes.
Typical C++: you can declare a class member variable "mutable" and then change it even from a const method.
The const keyword used after a method indicate that this method doesn't modify the object on which it's called. This way, this method can be called on a const version of the object.
If this is true, then should it be used everywhere, because i don't want ANY of the member variables to be altered or changed in any way?
Well, no. Sometimes you do want instance methods to modify members. For example, any set method will obviously need to set variables, so it's not the case that you should put const everywhere. But if your object's state is totally immutable, first consider whether it might not be better to have no instances at all (i.e., a static class), and if that's not the case, then make everything const.
It's quite unusual not to want to have any member variables changed, but if that's what your class requires, then you should make all your member functions const.
However, you probably do want to change at least some members:
class A {
private:
int val;
public:
A() : val(0) {}
void Inc() { val++; }
int GetVal() const { return val; };
};
Now if I create two instances of A:
A a1;
const A a2;
I can say:
a1.GetVal();
a2.GetVal();
but I can only say:
a1.Inc();
trying to change the value of a constant object:
a2.Inc();
gives a compilation error.

What does the const operator mean when used with a method in C++?

Given a declaration like this:
class A {
public:
void Foo() const;
};
What does it mean?
Google turns up this:
Member functions should be declared with the const keyword after them if they can operate on a const (this) object. If the function is not declared const, in can not be applied to a const object, and the compiler will give an error message.
But I find that somewhat confusing; can anyone out there put it in better terms?
Thanks.
Consider a variation of your class A.
class A {
public:
void Foo() const;
void Moo();
private:
int m_nState; // Could add mutable keyword if desired
int GetState() const { return m_nState; }
void SetState(int val) { m_nState = val; }
};
const A *A1 = new A();
A *A2 = new A();
A1->Foo(); // OK
A2->Foo(); // OK
A1->Moo(); // Error - Not allowed to call non-const function on const object instance
A2->Moo(); // OK
The const keyword on a function declaration indicates to the compiler that the function is contractually obligated not to modify the state of A. Thus you are unable to call non-const functions within A::Foo nor change the value of member variables.
To illustrate, Foo() may not invoke A::SetState as it is declared non-const, A::GetState however is ok because it is explicitly declared const. The member m_nState may not be changed either unless declared with the keyword mutable.
One example of this usage of const is for 'getter' functions to obtain the value of member variables.
#1800 Information: I forgot about mutable!
The mutable keyword instructs the compiler to accept modifications to the member variable which would otherwise cause a compiler error. It is used when the function needs to modify state but the object is considered logically consistent (constant) regardless of the modification.
This is not an answer, just a side comment. It is highly recommended to declare variables and constants const as much as possible.
This communicates your intent to users of your class (even/especially yourself).
The compiler will keep you honest to those intentions. -- i.e., it's like compiler checked documentation.
By definition, this prevents state changes you weren't expecting and can, possibly, allow you to make reasonable assumptions while in your methods.
const has a funny way of propagating through your code. Thus, it's a really good idea to start using const as early and as often as possible. Deciding to start const-ifying your code late in the game can be painful (easy, but annoying).
If you're using a language with static, compile time checks it's a great idea to make as much use of them as possible... it's just another kind of testing really.
Functions with const qualifier are not allowed to modify any member variables. For example:
class A
{
int x;
mutable int y;
void f() const
{
x = 1; // error
y = 1; // ok because y is mutable
}
};
C++ objects can be declared to be const:
const A obj = new A();
When an object is const, the only member functions that can be called on that object are functions declared to be const. Making an object const can be interpreted as making the object readonly. A const object cannot be changed, i.e. no data members of the object can be changed. Declaring a member function const means that the function is not allowed to make any changes to the data members of the object.
Two suggested best practices from experience:
(1) Declare const functions whenever possible. At first, I found this to be just extra work, but then I started passing my objects to functions with signatures like f(const Object& o), and suddenly the compiler barfed on a line in f such as o.GetAValue(), because I hadn't marked GetAValue as a const function. This can surprise you especially when you subclass something and don't mark your version of the virtual methods as const - in that case the compile could fail on some function you've never heard of before that was written for the base class.
(2) Avoid mutable variables when it's practical. A tempting trap can be to allow read operations to alter state, such as if you're building a "smart" object that does lazy or asynchronous i/o operations. If you can manage this with only one small mutable variable (like a bool), then, in my experience, this makes sense. However, if you find yourself marking every member variable as mutable in order to keep some operations const, you're defeating the purpose of the const keyword. What can go wrong is that a function which thinks it's not altering your class (since it only calls const methods) my invoke a bug in your code, and it could take a lot of effort to even realize this bug is in your class, since the other coder (rightly) assumes your data is const because he or she is only calling const methods.
const has a funny way of propagating through your code. Thus, it's a really good idea to start using const as early and as often as possible. Deciding to start const-ifying your code late in the game can be painful (easy, but annoying).
Additionally, you will easily run into problems if methods that should be const aren't! This will creep through the code as well, and make it worse and worse.
that will cause the method to not be able to alter any member variables of the object