Sell me const-correctness - c++

So why exactly is it that it's always recommended to use const as often as possible? It seems to me that using const can be more of a pain than a help in C++. But then again, I'm coming at this from the python perspective: if you don't want something to be changed, don't change it. So with that said, here are a few questions:
It seems like every time I mark something as const, I get an error and have to change some other function somewhere to be const too. Then this causes me to have to change another function somewhere else. Is this something that just gets easier with experience?
Are the benefits of using const really enough to compensate for the trouble? If you don't intend to change an object, why not just not write code that changes it?
I should note that at this point in time, I'm most focused on the benefits of using const for correctness and maintainability purposes, although it is also nice to have an idea of the performance implications.

This is the definitive article on "const correctness": https://isocpp.org/wiki/faq/const-correctness.
In a nutshell, using const is good practice because...
It protects you from accidentally changing variables that aren't intended be changed,
It protects you from making accidental variable assignments. For instance, you are protected from
if( x = y ) // whoops, meant if( x == y ).
The compiler can optimize it.
At the same time, the compiler can generate more efficient code because it knows exactly what the state of the variable/function will be at all times. If you are writing tight C++ code, this is good.
You are correct in that it can be difficult to use const-correctness consistently, but the end code is more concise and safer to program with. When you do a lot of C++ development, the benefits of this quickly manifest.

Here's a piece of code with a common error that const correctness can protect you against:
void foo(const int DEFCON)
{
if (DEFCON = 1) //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
{
fire_missiles();
}
}

It seems like every time I mark
something as const, I get an error and
have to change some other function
somewhere to be const too. Then this
causes me to have to change another
function somewhere else. Is this
something that just gets easier with
experience?
From experience, this is a total myth. It happens when non const-correct sits with const-correct code, sure. If you design const-correct from the start, this should NEVER be an issue. If you make something const, and then something else doesn't complile, the compiler is telling you something extremely important, and you should take the time to fix it properly.

If you use const rigorously, you'd be surprised how few real variables there are in most functions. Often no more than a loop counter. If your code is reaching that point, you get a warm feeling inside...validation by compilation...the realm of functional programming is nearby...you can almost touch it now...

It's not for you when you are writing the code initially. It's for someone else (or you a few months later) who is looking at the method declaration inside the class or interface to see what it does. Not modifying an object is a significant piece of information to glean from that.

Programming C++ without const is like driving without the safety belt on.
It's a pain to put the safety belt on each time you step in the car, and 364 out of 365 days you'll arrive safely.
The only difference is that when you get in trouble with your car you'll feel it immediately, whereas with programming without const you may have to search for two weeks what caused that crash only to find out that you inadvertently messed up a function argument that you passed by non-const reference for efficiency.

const is a promise your are making as a developer, and enlisting the compiler's help in enforcing.
My reasons for being const-correct:
It communicates to clients of your function that your will not change the variable or object
Accepting arguments by const reference gives you the efficiency of passing by reference with the safety of passing by value.
Writing your interfaces as const correct will enable clients to use them. If you write your interface to take in non-const references, clients who are using const will need to cast constness away in order to work with you. This is especially annoying if your interface accepts non-const char*'s, and your clients are using std::strings, since you can only get a const char* from them.
Using const will enlist the compiler in keeping you honest so you don't mistakenly change something that shouldn't change.

My philosophy is that if you're going to use a nit-picky language with compile time checks than make the best use of it you can. const is a compiler enforced way of communicating what you mean... it's better than comments or doxygen will ever be. You're paying the price, why not derive the value?

For embedded programming, using const judiciously when declaring global data structures can save a lot of RAM by causing the constant data to be located in ROM or flash without copying to RAM at boot time.
In everyday programming, using const carefully helps you avoid writing programs that crash or behave unpredictably because they attempt to modify string literals and other constant global data.
When working with other programmers on large projects, using const properly helps prevent the other programmers from throttling you.

const correctness is one of those things that really needs to be in place from the beginning. As you've found, its a big pain to add it on later, especially when there is a lot of dependency between the new functions you are adding and old non-const-correct functions that already exist.
In a lot of the code that I write, its really been worth the effort because we tend to use composition a lot:
class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };
If we did not have const-correctness, then you would have to resort to returning complex objects by value in order to assure yourself that nobody was manipulating class B's internal state behind your back.
In short, const-correctness is a defensive programming mechanism to save yourself from pain down the road.

const helps you isolate code that "change things" behind your back. So, in a class, you'd mark all methods that don't change the state of the object as const. This means that const instances of that class will no longer be able to call any non-const methods. This way, you're prevented from accidentally calling functionality that can change your object.
Also, const is part of the overload mechanism, so you can have two methods with identical signatures, but one with const and one without. The one with const is called for const references, and the other one is called for non-const references.
Example:
#include <iostream>
class HelloWorld {
bool hw_called;
public:
HelloWorld() : hw_called(false) {}
void hw() const {
std::cout << "Hello, world! (const)\n";
// hw_called = true; <-- not allowed
}
void hw() {
std::cout << "Hello, world! (non-const)\n";
hw_called = true;
}
};
int
main()
{
HelloWorld hw;
HelloWorld* phw1(&hw);
HelloWorld const* phw2(&hw);
hw.hw(); // calls non-const version
phw1->hw(); // calls non-const version
phw2->hw(); // calls const version
return 0;
}

Say you have a variable in Python. You know you aren't supposed to modify it. What if you accidentally do?
C++ gives you a way to protect yourself from accidentally doing something you weren't supposed to be able to do in the first place. Technically you can get around it anyways, but you have to put in extra work to shoot yourself.

There is a nice article here about const in c++. Its a pretty straight forward opinion but hope it helps some.

When you use the "const" keyword, you're specifying another interface to your classes. There is an interface that includes all methods, and an interface that includes only the const methods. Obviously this lets you restrict access to some things that you don't want changed.
Yes, it does get easier with time.

I like const correctness ... in theory. By every time I have tried to apply it rigourously in practice it has broken down eventually and const_cast starts to creep in making the code ugly.
Maybe it is just the design patterns I use, but const always ends up being too broad a brush.
For example, imagine a simple database engine ... it has schema objects, tables, fields etc. A user may have a 'const Table' pointer meaning that they are not allowed to modify the table schema itself ... but what about manipulating the data associated with the table? If the Insert() method is marked const then internally it has to cast the const-ness away to actually manipulate the database. If it isn't marked const then it doesn't protect against calling the AddField method.
Maybe the answer is to split the class up based on the const-ness requirements, but that tends to complicate the design more than I would like for the benefit it brings.

You can give the compiler hints with const as well....as per the following code
#include <string>
void f(const std::string& s)
{
}
void x( std::string& x)
{
}
void main()
{
f("blah");
x("blah"); // won't compile...
}

Related

What's the best way to deal with a non-const-aware Library/SDK?

I've been working for longer now with the 3ds max SDK, which in nearly all parts doesn't use const at all. So even a Width() or Height() getter of a Bitmap isn't marked as const. This has been already a real annoyance in small projects, but since I've been working on a larger project, it becomes increasingly terrible.
For example, I am holding a single Bitmap instance as a shared_ptr<Bitmap> member in multiple class instances out of performance reasons. Of course there are cases I want to avoid by all means that a single instance may change the properties for all instances, thus all raw pointer getters (necessary for the SDK) deliver a const Bitmap*. Unfortunately, now I can't even ask the const Bitmap* for its width - because Width() is non-const.
I'm asking myself what is the best way to deal with this. I see three options:
Forget about const completely, make everything non-const. In the smaller projects I used to do this, but like I said, with more sophisticated techniques, it becomes more dangerous.
Make an inplace const_cast at every place it's necessary. That will be at many places, and it's pretty bad to read.
Write wrappers for the 3ds max classes, which provide const methods at least for the methods which are highly presumably safe. This would encapsulate all the const_cast in one place and be also suitable for other projects.
I have been warned (and I know) that this might be opinion-based. But I had to deal with this annoying problem for a long time now, and I'd really like to find a solution and thus need the experience of others.
First of all, I would like to mention that lack of const correctness may be justifiable by implementation details, for example getter function may perform lock on internal synchronization primitive and therefore always alters internal state and can not be marked as const:
int Bitmap::Width(void)
{
int width{};
::std::lock_guard<::std::mutex> const lock{m_sync};
width = m_width;
return width;
}
As a workaround you can write a dedicated PImpl bitmap wrapper restricting direct access to bitmap implementation forwarding functions of interest with appropriate const qualifiers:
class SharedBitmap
{
private: ::std::shared_ptr<Bitmap> m_p_bitmap;
public: int Width(void) const
{
return m_p_bitmap->Width();
}
// other methods...
};
Note that this approach is different from third option listed in question as it does not involve const_cast.
In my experience (10yr), "const" has been a greater nusiance than it has been helpful. Not to mentions code getting longer, ergo harder to read. If you want to know how a library works, you read the manual anyway, not the header. If you want to know you did it right, you run functional tests. Hell there are even static analysis tools checking if a variable is ever written to, without burdening the code with useless non-functional metadata to capture undocumented usage patterns. And since there are a many ways to break const, it is the right way of capturing such errors.
In summary, option 1 is in my experience the most efficient solution. (Is this an opinion? Those who disagree will probably think so.)
For that quick post-purge of const you could do #define const or even -Dconst to remove it, though whether it is safe may depend on your specific scenario, one illegal use is doing this for the standard headers. I have done similar hacks like #define private|protected public instead of messing with friend when doing white box testing, works like a charm!
Know that the concept of "constant variable" is void in many programming languages and they seem to do just fine without it.
The only time you need const is in the case of C-string constants / string literals. Does not seem to be your case though.

C++ const accessors and references best practice

In attempting to brush up on my C++, I've been trying to find out the best-practice way of creating accessors.
I want to clarify my understanding and find out if what I'm doing is right. I have several questions, but they seem pretty simple so I've rolled them all into this one Stack Overflow question.
The following is some example code representing what I 'think' is the correct way of doing things:
class MyClass
{
private:
std::string StringMember_;
int IntMember_;
public:
MyClass(const std::string &stringInput, const int &intInput) : StringMember_(stringInput), IntMember_(intInput)
{
}
const std::string &StringMember() const
{
return StringMember_;
}
void StringMember(const std::string &stringInput)
{
StringMember_ = stringInput;
}
const int &IntMember() const
{
return IntMember_;
}
void IntMember(const int &intInput)
{
IntMember_ = intInput;
}
};
My questions are:
Where my accessors return a const reference variable, ie const std::string, this means that it (my class's member variable) cannot be changed. Is that correct?
The last const before a method's body indicates that no members of the class for which that method is a part of can be altered, unless they are designated mutable. Is this also correct?
Where I'm passing in const method parameters, this means that I ensure these parameters are always stored as they were passed in, thus protecting any original variables being passed in from being altered by the method body. Is this also correct?
With regards to the mutable keyword, under what circumstances would I actually want to use this? I've been struggling to think of a good scenario where I'd have a const method that needed to modify class members.
Accessors seem like a good idea, even for data that will never be publicly exposed, because it ensures a single-point of entry, allowing for easier debugging and so on. Am I thinking along the right lines here, or is this in fact totally meaningless, and that there is no need for private accessors?
From a purely syntactical perspective, should I be writing my references like const int& intInput or const int &intInput. Does it really matter where the ampersand is, or is it just a matter of personal preference?
Finally, is what I'm doing in the example above good practice? I plan to start working on a larger personal project, and I want to have these core basics down before I start running into problems later.
I was using this as a reference: https://isocpp.org/wiki/faq/const-correctness
Where my accessors return a const reference variable, ie const std::string, this means that it (my class's member variable) cannot be changed. Is that correct?
Correct. A variable cannot be changed through a const reference.
The last const before a method's body indicates that no members of the class for which that method is a part of can be altered, unless they are designated mutable. Is this also correct?
Correct. It also allows the function to be called on a const object.
Where I'm passing in const method parameters, this means that I ensure these parameters are always stored as they were passed in, thus protecting any original variables being passed in from being altered by the method body. Is this also correct?
Correct. Same can be achieved with accepting the argument by value.
With regards to the mutable keyword, under what circumstances would I actually want to use this?
See When have you used C++ 'mutable' keyword?
Accessors seem like a good idea, even for data that will never be publicly exposed, because it ensures a single-point of entry, allowing for easier debugging and so on. Am I thinking along the right lines here
I don't buy this argument. Watchpoints allow for easy debugging of member variables regardless of where they're accessed from.
From a purely syntactical perspective, should I be writing my references like const int& intInput or const int &intInput.
Both are syntactically equivalent and the choice between them is purely aesthetic.
Finally, is what I'm doing in the example above good practice?
There is no general answer. Accessors are sometimes useful. Often they're redundant. If you provide a function that allows setting the value directly, such as you do here, then you might as well get rid of the accessors and make the member public.
Seems to me like you have a pretty good handle on the concepts here. As far as a mutable example there are lots, here's one: you have a search method, and for performance reasons you cache the last search results... that internal cache would need to be mutable for a const search method. I.e. the external behavior didn't change, but internally something might change.
Here is some examples for mutable:
memoiziation caches, for when something is referencially-transparent,
but expensive to calculate, the first call to the (const-qualified)
accessor calculates the value and stores it in a mutable member hash
table, second and subsequent calls fetch the value from the table
instead.
access counters, timing, loggers, and other instrumentation that needs
to change some state when a const-qualified accessor is called
From https://www.quora.com/When-should-I-actually-use-a-mutable-keyword-in-C++

Can I use const references instead of getter functions?

I just wondered if I could bypass using getters if I just allowed a const reference variable, as follows
#include <string>
class cTest
{
private:
int m_i;
std::string m_str;
public:
const int & i;
const std::string & str;
cTest(void)
: i(m_i)
, str(m_str)
{}
};
int main(int argc, char *argv[])
{
cTest o;
int i = o.i; // works
o.i += 5; // fails
o.str.clear(); // fails
return 0;
}
I wonder why people do not seem to do this at all. Is there some severe disadvantage I am missing? Please contribute to the list of advantages and disadvantages, and correct them if necessary.
Advantages:
There is no overhead through calls of getter functions.
The program size is decreased because there are less functions.
I can still modify the internals of the class, the reference variables provide a layer of abstraction.
Disadvantages:
Instead of getter functions, I have a bunch of references. This increases the object size.
Using const_cast, people can mess up private members, but these people are mischievous, right?
Some severe disadvantages indeed (aside from the 2nd disadvantage that you also mention which I also put in the "severe" category):
1) You'll need to supply (and therefore maintain) a copy constructor: the compiler default will not work.
2) You'll need to supply an assignment operator: the compiler default will not work.
3) Think carefully about implementing the move semantics. Again, the compiler default will not work.
These three things mean the const reference anti-pattern you propose is a non-starter. Don't do it!
One advantage of getter functions is that you might at some point in time - want to alter returned value - and without getter function you cannot do it. This scenerio would require you to return non reference actually, which is less common in c++. [edit] but with move semantics instead of references this should be doable[/edit]
You might also want to put a breakpoint into getter function to learn who is reading its value, you might want to add logging, etc. This is called
encapsulation.
Other advantage of getter is that in debug builds you can add additional checks/asserts on returned data.
In the end compiler will inline your getter functions, which will result in similar code to the one you propose.
some additional disadvantage:
1) template code will want to get values using function call, ie. size(), if you change it to const& variable then you will not be able to use it in some templates. So this is a consistency problem.
If you want to avoid getters and setters, using a const reference member is not the solution.
Instead, you'll want to ensure const correctness on the surrounding struct (which automagically gives you const access to the members), and just let the members be whatever they logically need to be.
Be sure to read up on when getters and setters can, should, or could be switched with public data members. See e.g. this question. Just note that if you change the interface, the heralded dvantage of setters/getters is that calling the getter won't affect call sites. Reality seems to argue otherwise, and e.g. refactoring a member along with all its access points is a trivial operation for any self-respecting C++ code editor.
Although one could argue for encapsulation, I'd more strongly argue for const correctness, which alleviates the need for much encapsulation and really simplifies code quite a lot.

Does it make sense to use const in an interface or not?

I have a module that performs some calculations and during the calculations, communicates with other modules. Since the calculation module does not want to rely on the other modules, it exposes an interface like this (this is a very simplified version of course):
class ICalculationManager
{
public:
double getValue (size_t index) = 0;
void setValue (size_t index, double value) = 0;
void notify (const char *message) = 0;
};
Applications that want to use the calculation module need to write their own implementation of the interface, and feed it to the calculation tool, like this:
MyCalculationManager calcMgr;
CalculationTool calcTool (calcMgr);
calcTool.calculate();
I am wondering now whether it makes sense to add "const" to the methods of the ICalculationManager interface.
It would seem logical that the getValue method only gets something and doesn't change anything, so I could make this const. And setValue probably changes data so that won't be const.
But for a more general method like notify I can't be sure.
In fact, for none of the methods I can now for sure that the method is really implemented as a const method, and if I would make the interface methods const, I am forcing all implementations to be const as well, which is possibly not wanted.
It seems to me that const methods only make sense if you know beforehand what your implementation will be and whether it will be const or not. Is this true?
Doesn't it make sense to make methods of this kind of interface const? And if it makes sense, what are good rules to determine whether the method should be const or not, even if I don't know what the implementation will be?
EDIT: changed the parameter from notify from "char *" to "const char *" since this lead to irrelevant answers.
You make a function const when you are advertising to clients that calling the function will never change the externally visible state of the object. Your object only has one piece of state that can be retrieved, getValue.
So, if getValue can cause the next getValue to return a different value then sure, leave it non-const. If you want to tell clients that calling getValue() will never change the value returned by the next getValue() then make it const.
Same for notify:
double d1 = mgr->getValue(i);
mgr->notify("SNTH"); // I'm cheating.
double d2 = mgr->getValue(i);
assert(d1==d2);
If that should hold true for all cases and all i's then notify() should be const. Otherwise it should not be.
Yes. One should use const whenever and wherever it is sensible to do so. It doesn't make sense that the method for performing a calculation (which is what your interface suggests) should change it's observable behavior because it had "notify" called on it. (And for that matter, how is notification related to calculation at all?)
My making one of the interface members const, you don't force clients to be const -- you merely allow them use of a const ICalculationManager.
I would probably make Notify const. If clients need to do something non-const as a result of a notification, then Notify is not a good method name -- that name suggest non-state-modifying transformations such as logging, not modification.
For instance, most of the time you pass your interface around, you're going to want to use pass-by-reference-to-const to pass the interface implementor, but if the methods aren't const, you cannot do that.
The interface should be guiding the implementation, not the other way around. If you haven't decided if a method or parameter can be const or not, you're not done designing.
Using const is a way of making assertions about what the code is or is not allowed to do. This is extremely valuable in reasoning about a piece of code. If your parameter to notify isn't const for example, what changes would it make to the message? How would it make the message larger if it needed to?
Edit: You appear to know the value of declaring a const parameter, so lets build on that. Suppose you want a function to record the value of a calculation:
void RecordCalculation(const ICalculationManager *calculation);
The only methods you'll be able to call on that pointer are the const methods. You can be sure that after the function returns, the object will be unchanged. This is what I meant by reasoning about the code - you can be absolutely certain the object won't be changed, because the compiler will generate an error if you try.
Edit 2: If your object contains some internal state that will be modified in response to operations that are logically const, such as a cache or buffer, go ahead and use the mutable keyword on those members. That's what it was invented for.
For me it only depends on the contract of your interface.
For a getter method I do not see why it should change any data and if this happens, maybe mutable is an option.
For the setter method I agree, not const there because this will certainly change data somehow.
For the notify is hard to say without knowing what it means for your system. Also, do you expect the message parameter to be modified by the implementation? If now, it should be const too.
Without reading your entire post: Yes of course, it makes sense if you want to use an object (which inherits ICalculationManager) in a const context. Generally, you should always use const qualifier if you don't manipulate private data.
EDIT:
Like Mark Ransom said: You need to know exactly how your interface functions should behave, otherwise your not finished designing.
I know I'm going to get a lot of downvotes for this, but in my opinion the usefulness of const-correctness in C++ is vastly exaggerated. The const idea is primitive (it only captures one bit of concept... change/don't change) and comes with an high cost that even includes necessity of code duplication. Also it doesn't scale well (consider const_iterators).
What's more important I cannot remember even a single case (not even ONE) in which the const-correctness machinery helped me by spotting a true logical error, that is I was trying to do something that I shouldn't do. Instead every single time the compiler stopped me there was a problem in the const declaration part (i.e. what I was trying to do was logically legit, but a method or a parameter had a problem in the declaration about const-ness).
In all cases I can remember where I got a compiler error related to const-correctness the fix was just adding some missing const keywords or removing some that were in excess... without using the const-correctness idea those errors wouldn't have been there at all.
I like C++, but of course I don't love to death every bit of it (digression: when I interview someone a question I often ask is "what is the part you don't like about <language> ?" ... if the answer is "none" then simply means that who I'm talking to is still in the fanboy stage and clearly doesn't have a big real experience).
There are many parts of C++ that are very good, parts that are IMO horrible (stream formatting, for example) and parts that are not horrible but neither logically beautiful nor practically useful. Const-correctness idea is IMO in this gray area (and this is not a newbie impression... I came to this conclusion after many many lines and years of coding in C++).
May be it's me, but apparently const correctness solves a problem that my brain doesn't have ... I've many others problems, but not the one of confusing when I should change an instance state and when I shouldn't.
Unfortunately (differently from stream formatting) you cannot just ignore the const-correctness machinery in C++ because it's part of the core language, so even if I don't like it I'm forced to comply with it anyway.
You may now say... ok, but what's the answer to the question ? It's simply that I wouldn't get too crazy about that part of the semantic description... it's just a single bit and comes with an high price; if you're unsure and you can get away without declaring constness then don't do it. Constness of references or methods is never an help for the compiler (remember that it can be legally casted away) and it has been added to C++ just as an help for programmers. My experience tells me however that (given the high cost and the low return) it's not a real help at all.

"get() const" vs. "getAsConst() const"

Someone told me about a C++ style difference in their team. I have my own viewpoint on the subject, but I would be interested by pros and cons coming from everyone.
So, in case you have a class property you want to expose via two getters, one read/write, and the other, readonly (i.e. there is no set method). There are at least two ways of doing it:
class T ;
class MethodA
{
public :
const T & get() const ;
T & get() ;
// etc.
} ;
class MethodB
{
public :
const T & getAsConst() const ;
T & get() ;
// etc.
} ;
What would be the pros and the cons of each method?
I am interested more by C++ technical/semantic reasons, but style reasons are welcome, too.
Note that MethodB has one major technical drawback (hint: in generic code).
C++ should be perfectly capable to cope with method A in almost all situations. I always use it, and I never had a problem.
Method B is, in my opinion, a case of violation of OnceAndOnlyOnce. And, now you need to go figure out whether you're dealing with const reference to write the code that compiles first time.
I guess this is a stylistic thing - technically they both works, but MethodA makes the compiler to work a bit harder. To me, it's a good thing.
Well, for one thing, getAsConst must be called when the 'this' pointer is const -- not when you want to receive a const object. So, alongside any other issues, it's subtly misnamed. (You can still call it when 'this' is non-const, but that's neither here nor there.)
Ignoring that, getAsConst earns you nothing, and puts an undue burden on the developer using the interface. Instead of just calling "get" and knowing he's getting what he needs, now he has to ascertain whether or not he's currently using a const variable, and if the new object he's grabbing needs to be const. And later, if both objects become non-const due to some refactoring, he's got to switch out his call.
Personally, I prefer the first method, because it makes for a more consistent interface. Also, to me getAsConst() sounds just about as silly as getAsInt().
On a different note, you really should think twice before returning a non-const reference or a non-const pointer to a data member of your class. This is an invitation for people to exploit the inner workings of your class, which ideally should be hidden. In other words it breaks encapsulation. I would use a get() const and a set(), and return a non-const reference only if there is no other way, or when it really makes sense, such as to give read/write access to an element of an array or a matrix.
Given the style precedent set by the standard library (ie begin() and begin() const to name just one example), it should be obvious that method A is the correct choice. I question the person's sanity that chooses method B.
So, the first style is generally preferable.
We do use a variation of the second style quite a bit in the codebase I'm currently working on though, because we want a big distinction between const and non-const usage.
In my specific example, we have getTessellation and getMutableTessellation. It's implemented with a copy-on-write pointer. For performance reasons we want the const version to be use wherever possible, so we make the name shorter, and we make it a different name so people don't accidentally cause a copy when they weren't going to write anyway.
While it appears your question only addresses one method, I'd be happy to give my input on style. Personally, for style reasons, I prefer the former. Most IDEs will pop up the type signature of functions for you.
I would prefer the first. It looks better in code when two things that essentially do the same thing look the same. Also, it is rare for you to have a non-const object but want to call the const method, so that isn't much of a consern (and in the worst case, you'd only need a const_cast<>).
The first allows changes to the variable type (whether it is const or not) without further modification of the code. Of course, this means that there is no notification to the developer that this might have changed from the intended path. So it's really whether you value being able to quickly refactor, or having the extra safety net.
The second one is something related to Hungarian notation which I personally DON'T like so I will stick with the first method.
I don't like Hungarian notation because it adds redundancy which I usually detest in programming. It is just my opinion.
Since you hide the names of the classes, this food for thought on style may or may not apply:
Does it make sense to tell these two objects, MethodA and MethodB, to "get" or "getAsConst"? Would you send "get" or "getAsConst" as messages to either object?
The way I see it, as the sender of the message / invoker of the method, you are the one getting the value; so in response to this "get" message, you are sending some message to MethodA / MethodB, the result of which is the value you need to get.
Example: If the caller of MethodA is, say, a service in SOA, and MethodA is a repository, then inside the service's get_A(), call MethodA.find_A_by_criteria(...).
The major technological drawback of MethodB I saw is that when applying generic code to it, we must double the code to handle both the const and the non-const version. For example:
Let's say T is an order-able object (ie, we can compare to objects of type T with operator <), and let's say we want to find the max between two MethodA (resp. two MethodB).
For MethodA, all we need to code is:
template <typename T>
T & getMax(T & p_oLeft, T & p_oRight)
{
if(p_oLeft.get() > p_oRight.get())
{
return p_oLeft ;
}
else
{
return p_oRight ;
}
}
This code will work both with const objects and non-const objects of type T:
// Ok
const MethodA oA_C0(), oA_C1() ;
const MethodA & oA_CResult = getMax(oA_C0, oA_C1) ;
// Ok again
MethodA oA_0(), oA_1() ;
MethodA & oA_Result = getMax(oA_0, oA_1) ;
The problem comes when we want to apply this easy code to something following the MethodB convention:
// NOT Ok
const MethodB oB_C0(), oB_C1() ;
const MethodB & oB_CResult = getMax(oB_C0, oB_C1) ; // Won't compile
// Ok
MethodA oB_0(), oB_1() ;
MethodA & oB_Result = getMax(oB_0, oB_1) ;
For the MethodB to work on both const and non-const version, we must both use the already defined getMax, but add to it the following version of getMax:
template <typename T>
const T & getMax(const T & p_oLeft, const T & p_oRight)
{
if(p_oLeft.getAsConst() > p_oRight.getAsConst())
{
return p_oLeft ;
}
else
{
return p_oRight ;
}
}
Conclusion, by not trusting the compiler on const-ness use, we burden ourselves with the creation of two generic functions when one should have been enough.
Of course, with enough paranoia, the secondth template function should have been called getMaxAsConst... And thus, the problem would propagate itself through all the code...
:-p