Constant Member Functions - c++

After reading this, it is my understanding that declaring a method as const prevents it from accidentally modifying the class's member variables.
Are const methods commonly used?
Should they be used for everything that shouldn't modify member variables?

Yes, const should always be used, when appropriate.
It lets your compiler check your application logic, statically asserting const-correctness for free!
Some people even say that const should be the default, and you should be forced to use mutable for what is non-constant.

I use const extensively to communicate design intent. If I intended that a method was a pure query, and not a modification function, I would both enforce that and communicate it with a 'const' in the signature.
I encourage you to look at Meyer's thoughts on the matter of side-effect-free functions, and the implications that has on enabling testing.

Just my testimony.
Some years ago, I was still against the use of const, just because of the constraints in design and writing longer function signatures... and so on...
But one of my project leaders always insisted, all the time, reminding me: "You should use const function, it avoids accidents and doing non-sense".
And one day I faced an impossible bug to find. Days after days after days... A nightmare. The design was too big for me too see so as I could grasp it in its whole. I searched in vain until I decided I was lost.
Then I spent two days redefining ALL the functions that should be const. I mean it, two days. (Recompilations were long as it was a 5 millions lines of code project).
And then: simply I found the bug... rather the Compiler found the bug for me: In a getter-like method, which should have given me the prefered size of a gui control, the code was actually computing the size, but it was also caching its size and updating its size... Thus modifying the object.
Now, sometimes I forget to put const. But if I notice it, I correct it.

Adding const to a member function allows it to be called on const references to an object, because it guarantees that instance variables won't be changed. Const references occur in various places throughout the STL, so it makes sense to mark member functions as const where the function doesn't intend to modify the state of an object.
Note: it is possible to mark certain instance variables as mutable so they can be changed even by const functions. This is useful to implement look-up caches, for example.

Declaring a method that shouldn't modify member variables:
Assures that what you think is what is happening, i.e. that you're not accidentally modifying a variable somewhere.
Declares to callers of the function that this method doesn't modify member variables, removing the need to read over the code or rely on documentation that says so.
So yes, use const wherever it makes sense. They're not as widely used as I'd like to see though, most likely because the majority of developers don't see the huge benefit.

If you forget to mark an accessor as const, the compiler will not allow the method to be called on const objects or references to const objects. So yes, marking accessors as const is important.

If you have a const reference or pointer (i.e. pointer to const) of a class object then you can ONLY call const member methods of the class.
So if someone "forgot" to make a "get" method const, you would not be able to call it with a const reference (There is a workaround with const_cast but we don't want to use that!).
So yes, if the class is not going to be modified by the method then it should be const.
Note: there are some occasions that you do want to modify a variable as an "implementation detail", eg lazy-loading or to lock a mutex. In such a case you can still make the method const but make that member variable "mutable".
If you are writing a virtual method, it should be const if no derived class will need it to be mutable.

You should use the const keyword whenever possible.
It prevent you from the mistakes in the code.
It increase the readability of the code very much.
Everyone who is reading the header and seeing const keywords can immediately understand that a const method does not change the state of an object and can be used with no being afraid he will change the object for example

Related

Can you mutate an object of custom type when it's declared as constant?

In our codebase, Pytorch, there are several areas where an object is declared as const but the object's member variables are eventually modified. e.g., see https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/Resize.cpp#L29
This particular function here ends up modifying output, which is declared as const. Under what situations can you modify an object declared as const and is there an acceptable practice on whether or not this should be done?
It is doing so through a (eventual) call to TensorBase::unsafeGetTensorImpl which returns TensorBase*, a mutable pointer, even though is declared as const and as such is safe to call in this scenario.
As the method name suggests, this is unsafe.
You can, but you are betraying your users
A lot of times we get hung up on what we can do and/or get away with. But we forget that programming is designed for humans to communicate ideas. And the programming environment is designed to help us do that correctly and succinctly.
So yes, you could, at any time, throw off the constness of your target object(s) and do what you like. If you are lucky no future user will find a way and attempt to pass something that is actually in a section of memory marked as read-only.
But the purpose of marking a thing as “const” is that you (the programmer) personally guarantee the users of a function/method/whatever that it will not attempt to modify the object, for any reason.
To then sneakily modify it behind your users’ collective back, totally outside their expectations, is just plain Wrong™.
Don’t do it.
Consequently, I suggest you recommend fixing your codebase to be correct: remove the consts. It will not break any existing code using it, so that helps if you need to convince anyone to make your interface declare itself truthfully.
EDIT: An “output” object should never be “const” anyway. Functional languages like Haskell, for example, go through a lot of pains to separate mutable output and immutable objects (via Monads, in case you are curious to read more).

Const-correctness and hardware writes

Say I have the following member function:
void CFoo::regWrite( int addr, int data )
{
reg_write( addr, data ); // driver call to e.g. write a firmware register
}
Clearly, calling this function doesn't modify the internal state of the object it is called on. However, it changes the state of whatever this Foo instance represents.
In circumstances such as these, should Foo::regWrite(int addr, int data) be a const function?
You have to decide what the meaning is of "logically const" for the class CFoo, and that depends what the class is for.
If CFoo is construed as referring to some data, then it might make sense to be able to modify that data via a const instance of CFoo, in which case your member function would be const. For examples of this consider other types that refer to some data -- you can modify the referand of a char *const or a const std::unique_ptr<char>.
If CFoo is construed as owning some data, then it might make sense to forbid modification via a const instance of CFoo. For examples of this consider containers, where the elements are logically "part of the object's state" even when they aren't physically part of the object. So vector::operator[] has a const overload that returns a const T& rather than a T&, the insert member function is non-const, etc.
It is up to the programmer to define what 'const' shall mean for a class. With the specifier mutable you can even have a constobject with changing values in a member. When it comes to hardware one might consider the configuration as the target for const correctness: as long as the configuration does not change the object can be considered constant.
A similar issue rises if you have pointers to other objects in your class: Your const method can then call non-const methods on the other object and thus modifiy it.
If you look at the hardware as as some other object referenced by your class, it would be perfectly valid to modify firmware settings (since only a "referenced" object is changed). If you want your class to "represent" the hardware (or part of it), I would rather suggest not to mark the method as const.
So I think it mainly depends how you designed your class.
There are two ways of looking at this - the optimization angle, and the logic of this declaration. Which is more important is for you to decide.
Optimization
EDIT: I made some incorrect assumptions. It seems the compiler is not actually free to make the optimizations below, and will only make them by analyzing the body of the method to ensure no modifications occur (and even then only in simple cases).
Having this const will allow the compiler to optimize a little bit
more. It knows that regWrite doesn't change any fields in the
object, so it can keep them if it was storing them in registers, and
do similar optimizations that rely on the objects fields not being
changed.
This is really the only thing the compiler will depend on when you
make a definition like this, so having this const is OK and can
theoretically allow better performance.
Making logical sense
It feels unintuitive to have a const method whose whole purpose is a destructive change. The usual intuition a programmer has is that as long as I'm only calling const methods, the results of other const methods shouldn't change. If you violate this unwritten contract, expect people to be surprised - even if the compiler is OK with it.
I'm not sure if this will be violated here - it will depend on the other code in this class. However, if no other considerations are important (performance, etc.), const is (for me) mostly a marker on the interface which says "calling this does not change the state of this object", for a broad definition of "state".
This is murky ground however, and it is up to you what you consider a state change. If you think of your firmware object as representing a link to the internals, writing a register does not change anything about this link and is const. If you think of it as representing the state of the underlying registers, than writing to registers is a change of state.

is it good practice to add const at end of member functions - where appropriate?

Is it a good practice, in C++, to add const at the end of a member function definition every time the function does not modify the object, i.e., every time the function is 'eligible' for const?
I know that it's necessary in this case:
class MyClass {
public:
int getData() const;
};
void function(const MyClass &m) { int a = m.getData(); dosomething... }
but other than this, and other uses of const for actual functionality, does adding const to the end actually change the way code is executed (faster/slower) or is it just a 'flag' for the compiler to handle cases such as the one above?
In other words, if const (at the end) is not needed for functionality in a class, does adding it make any difference?
Please see this excellent article about const correctness by Herb Sutter (C++ standards committee secretary for 10 years.)
Regarding optimizations, he later wrote this article where he states that "const is mainly for humans, rather than for compilers and optimizers." Optimizations are impossible because "too many things could go wrong...[your function] might perform const_casts."
However, const correctness is a good idea for two reasons: It is a cheap (in terms of your time) assertion that can find bugs; and, it signals the intention that a function should theoretically not modify the object's external state, which makes code easier to understand.
every time the function does not modify the object, i.e., every time the function is 'eligible' for const?
In my opinion, Yes. It ensures that you call such functions on const objects or const expressions involving the object:
void f(const A & a)
{
a.inspect(); //inspect must be a const member function.
}
Even if it modifies one or few internal variables once or twice, even then I usually make it const member function. And those variables are declared with mutable keyword:
class A
{
mutable bool initialized_cache; //mutable is must!
public:
void inspect() const //const member function
{
if ( !initialized_cache)
{
initialized_cache= true;
//todo: initialize cache here
}
//other code
}
};
Yes. In general, every function that is logically const should be made const. The only gray areas are where you modify a member through a pointer (where it can be made const but arguably should not be const) or where you modify a member that is used to cache a computation but otherwise has no effect (which arguably should be made const, but will require the use of the keyword mutable to do so).
The reason why it's incredibly important to use the word const is:
It is important documentation to other developers. Developers will assume that anything marked const does not mutate the object (which is why it might not be a good idea to use const when mutating state through a pointer object), and will assume that anything not marked const mutates.
It will cause the compiler to catch unintentional mutations (by causing an error if a function marked const unintintionally calls a non-const function or mutates an element).
Yes, it is a good practice.
At the software engineering level it allows you to have read-only objects, e.g. you can prevent objects from being modified by making them const. And if an object is const, you are only allowed to call const functions on it.
Furthermore, I believe the compiler can make certain optimizations if it he knows that an object will only be read (e.g., share common data between several instances of the object as we know they are never being modified).
The 'const' system is one of the really messy features of C++. It is simple in concept, variables declared with ‘const’ added become constants and cannot be altered by the program, but, in the way is has to be used to bodge in a substitute for one of the missing features of C++, it gets horridly complicated and frustratingly restrictive. The following attempts to explain how 'const' is used and why it exists. Of the mixes of pointers and ‘const’, the constant pointer to a variable is useful for storage that can be changed in value but not moved in memory and the pointer (constant or otherwise) is useful for returning constant strings and arrays from functions which, because they are implemented as pointers, the program could otherwise try to alter and crash. Instead of a difficult to track down crash, the attempt to alter unalterable values will be detected during compilation.
For example, if a function which returns a fixed ‘Some text’ string is written like
char *Function1()
{ return “Some text”;}
then the program could crash if it accidentally tried to alter the value doing
Function1()[1]=’a’;
whereas the compiler would have spotted the error if the original function had been written
const char *Function1()
{ return "Some text";}
because the compiler would then know that the value was unalterable. (Of course, the compiler could theoretically have worked that out anyway but C is not that clever.)
When a subroutine or function is called with parameters, variables passed as the parameters might be read from to transfer data into the subroutine/function, written to to transfer data back to the calling program or both to do both. Some languages enable one to specify this directly, such as having ‘in:’, ‘out:’ & ‘inout:’ parameter types, whereas in C one has to work at a lower level and specify the method for passing the variables choosing one that also allows the desired data transfer direction.
For example, a subroutine like
void Subroutine1(int Parameter1)
{ printf("%d",Parameter1);}
accepts the parameter passed to it in the default C & C++ way which is a copy. Therefore the subroutine can read the value of the variable passed to it but not alter it because any alterations it makes are only made to the copy and lost when the subroutine ends so
void Subroutine2(int Parameter1)
{ Parameter1=96;}
would leave the variable it was called with unchanged not set to 96.
The addition of an ‘&’ to the parameter name in C++ (which was a very confusing choice of symbol because an ‘&’ infront of variables elsewhere in C generate pointers!) like causes the actual variable itself, rather than a copy, to be used as the parameter in the subroutine and therefore can be written to thereby passing data back out the subroutine. Therefore
void Subroutine3(int &Parameter1)
{ Parameter1=96;}
would set the variable it was called with to 96. This method of passing a variable as itself rather than a copy is called a ‘reference’ in C.
That way of passing variables was a C++ addition to C. To pass an alterable variable in original C, a rather involved method using a pointer to the variable as the parameter then altering what it pointed to was used. For example
void Subroutine4(int *Parameter1)
{ *Parameter1=96;}
works but requires the every use of the variable in the called routine so altered and the calling routine altered to pass a pointer to the variable which is rather cumbersome.
But where does ‘const’ come into this? Well, there is a second common use for passing data by reference or pointer instead of copy. That is when copying a the variable would waste too much memory or take too long. This is particularly likely with large compound user-defined variable types (‘structures’ in C & ‘classes’ in C++). So a subroutine declared
void Subroutine4(big_structure_type &Parameter1);
might being using ‘&’ because it is going to alter the variable passed to it or it might just be to save copying time and there is no way to tell which it is if the function is compiled in someone else’s library. This could be a risk if one needs to trust the the subroutine not to alter the variable.
To solve this, ‘const’ can be used the in the parameter list like
void Subroutine4(big_structure_type const &Parameter1);
which will cause the variable to passed without copying but stop it from then being altered. This is messy because it is essentially making an in-only variable passing method from a both-ways variable passing method which was itself made from an in-only variable passing method just to trick the compiler into doing some optimization.
Ideally, the programmer should not need control this detail of specifying exactly how it variables are passed, just say which direction the information goes and leave the compiler to optimize it automatically, but C was designed for raw low-level programming on far less powerful computers than are standard these days so the programmer has to do it explicitly.
My understanding is that it is indeed just a flag. However, that said, you want to add it wherever you can. If you fail to add it, and a function elsewhere in your code does something like
void function(const MyClass& foo)
{
foo.getData();
}
You will run into issues, for the compiler cannot guarantee that getData does not modify foo.
Making member functions const ensures that calling code that has const objects can still call the function. It is about this compiler check - which helps create robust self-documenting code and avoid accidental modifications of objects - and not about run-time performance. So yes, you should always add const if the nature of the function is such that it doesn't need to modify the observable value of the object (it can still modify member variables explicitly prefixed with the mutable keyword, which is intended for some quirky uses like internal caches and counters that don't affect the client-visible behaviour of the object).

Good Practice: To Modify Only Function Parameters?

Say, I develop a complex application: Within object member functions, should I modify only those objects, that are passed to the member functions as parameters, or can I access and modify any other objects I have access to(say public or static objects)?
Technically, I know that it is possible to modify anything I have access to. I am asking about good practices.
Sometimes, it is bothering to pass as an argument everythying i will access and modify, especially if I know that the object member function will not be used by anybody else, but me. Thanks.
Global state is never a good idea (though it is sometimes simpler, for example logging), because it introduces dependencies that are not documented in the interface and increase coupling between components. Therefore, modifying a global state (static variables for example) should be avoided at all costs. Note: global constants are perfectly okay
In C++, you have the const keyword, to document (and have the compiler enforce) what can be modified and what cannot.
A const method is a guarantee that the visible state of an object will be untouched, an argument passed by const reference, or value, will not be touched either.
As long as it is documented, it is fine... and you should strive for having as few non-const methods in your class interface and as few non-const parameters in your methods.
If you have a class with member variables, then it is entirely acceptable to modify those member variables in a member method regardless of whether those member variables are private, protected, or public. This is want is meant by encapsulation.
In fact, modifying the variables passed into the member method is probably a bad idea; returning a new value is what you'd want, or getting a new value back from a separate member method.

When should a member function have a const qualifier and when shouldn't it?

About six years ago, a software engineer named Harri Porten wrote this article, asking the question, "When should a member function have a const qualifier and when shouldn't it?" I found it to be the best write-up I could find of the issue, which I've been wrestling with more recently and which I think is not well covered in most discussions I've found on const correctness. Since a software information-sharing site as powerful as SO didn't exist back then, I'd like to resurrect the question here.
The article seems to cover a lot of basic ground, but the author still has a question about const and non-const overloads of functions returning pointers. Last line of the article is:
Many will probably answer "It depends." but I'd like to ask "It depends on what?"
To be absolutely precise, it depends whether the state of the A object pointee is logically part of the state of this object.
For an example where it is, vector<int>::operator[] returns a reference to an int. The int referand is "part of" the vector, although it isn't actually a data member. So the const-overload idiom applies: change an element and you've changed the vector.
For an example where it isn't, consider shared_ptr. This has the member function T * operator->() const;, because it makes logical sense to have a const smart pointer to a non-const object. The referand is not part of the smart pointer: modifying it does not change the smart pointer. So the question of whether you can "reseat" a smart pointer to refer to a different object is independent of whether or not the referand is const.
I don't think I can provide any complete guidelines to let you decide whether the pointee is logically part of the object or not. However, if modifying the pointee changes the return values or other behaviour of any member functions of this, and especially if the pointee participates in operator==, then chances are it is logically part of this object.
I would err on the side of assuming it is part (and provide overloads). Then if a situation arose where the compiler complains that I'm trying to modify the A object returned from a const object, I'd consider whether I really should be doing that or not, and if so change the design so that only the pointer-to-A is conceptually part of the object's state, not the A itself. This of course requires ensuring that modifying the A doesn't do anything that breaks the expected behaviour of this const object.
If you're publishing the interface you may have to figure this out in advance, but in practice going back from the const overloads to the const-function-returning-non-const-pointer is unlikely to break client code. Anyway, by the time you publish an interface you hopefully have used it a bit, and probably got a feel for what the state of your object really includes.
Btw, I also try to err on the side of not providing pointer/reference accessors, especially modifiable ones. That's really a separate issue (Law of Demeter and all that), but the more times you can replace:
A *getA();
const A *getA() const;
with:
A getA() const; // or const A &getA() const; to avoid a copy
void setA(const A &a);
The less times you have to worry about the issue. Of course the latter has its own limitations.
One interesting rule of thumb I found while researching this came from here:
A good rule of thumb for LogicalConst is as follows: If an operation preserves LogicalConstness, then if the old state and the new state are compared with the EqualityOperator, the result should be true. In other words, the EqualityOperator should reflect the logical state of the object.
I personally use a very simple Rule Of Thumb:
If the observable state of an object does not change when calling a given method, this method ought to be const.
In general it is similar to the rule mentioned by SCFrench about Equality Comparison, except that most of my classes cannot be compared.
I would like to push the debate one step further though:
When requiring an argument, a function ought to take it by const handle (or copy) if the argument is left unchanged (for an external observer)
It is slightly more general, since after all the method of a class is nothing else than a free-standing function accepting an instance of the class as a first argument:
class Foo { void bar() const; };
is equivalent to:
class Foo { friend void bar(const Foo& self); }; // ALA Python
when it doesn't modify the object.
It simply makes this to have type const myclass*. This guarantees a calling function that the object won't change. Allowing some optimizations to the compiler, and easier for the programmer to know if he can call it without side effects (at least effects to the object).
General rule:
A member function should be const if it both compiles when marked as const and if it would still compile if const were transitive w.r.t pointers.
Exceptions:
Logically const operations; methods that alter internal state but that alteration is not detectable using the class's interface. Splay tree queries for example.
Methods where the const/non-const implementations differ only by return type (common with methods the return iterator/const_iterator). Calling the non-const version in the const version via a const_cast is acceptable to avoid repetition.
Methods interfacing to 3rd party C++ that isn't const correct, or to code written in a language that doesn't support const
Here are some good articles:
Herb Sutter's GotW #6
Herb Sutter & const for optimizations
More advice on const correctness
From Wikipedia
I use const method qualifiers when the method does not alter the class' data members or its common intent is not to modify the data members. One example involves RAII for a getter method that may have to initialize a data members (such as retrieve from a database). In this example, the method only modifies the data member(s) once during initialization; all other times it is constant.
I'm allowing the compiler to catch const errors during compile time rather than me catching them during run-time (or a User).