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++
Related
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.
I was trying to write down some implementations for a couple of data structures that I'm interested in for a multithreaded / concurrent scenario.
A lot of functional languages, pretty much all that I know of, design their own data structures in such a way that they are immutable, so this means that if you are going to add value to an instance t1 of T, you really get a new instance of T that packs t1 + value.
container t;
container s = t; //t and s refer to the same container.
t.add(value); //this makes a copy of t, and t is the copy
I can't find the appropriate keywords to do this in C++11; there are keywords, semantics and functions from the standard library that are clearly oriented to the functional approach, in particular I found that:
mutable it's not for runtime, it's more likely to be an hint for the compiler, but this keyword doesn't really help you in designing a new data structure or use a data structure in an immutable way
swap doesn't works on temporaries, and this is a big downside in my case
I also don't know how much the other keywords / functions can help with such design, swap was one of them really close to something good, so I could at least start to write something, but apparently it's limited to lvalues .
So I'm asking: it's possible to design immutable data structure in C++11 with a functional approach ?
You simply declare a class with private member variables and you don't provide any methods to change the value of these private members. That's it. You initialize the members only from the constructors of the class. Noone will be able to change the data of the class this way. The tool of C++ to create immutable objects is the private visibility of the members.
mutable: This is one of the biggest hacks in C++. I've seen at most 2 places in my whole life where its usage was reasonable and this keyword is pretty much the opposite of what you are searching for. If you would search for a keyword in C++ that helps you at compile time to mark data members then you are searching for the const keyword. If you mark a class member as const then you can initialize it only from the INITIALIZER LIST of constructors and you can no longer modify them throughout the lifetime of the instance. And this is not C++11, it is pure C++. There are no magic language features to provide immutability, you can do that only by programming smartly.
In c++ "immutability" is granted by the const keyword. Sure - you still can change a const variable, but you have to do it on purpose (like here). In normal cases, the compiler won't let you do that. Since your biggest concern seems to be doing it in a functional style, and you want a structure, you can define it yourself like this:
class Immutable{
Immutable& operator=(const Immutable& b){} // This is private, so it can't be called from outside
const int myHiddenValue;
public:
operator const int(){return myHiddenValue;}
Immutable(int valueGivenUponCreation): myHiddenValue(valueGivenUponCreation){}
};
If you define a class like that, even if you try to change myHiddenValue with const_cast, it won't actually do anything, since the value will be copied during the call to operator const int.
Note: there's no real reason to do this, but hey - it's your wish.
Also note: since pointers exist in C++, you still can change the value with some kind of pointer magic (get the address of the object, calc the offset, etc), but you can't really help that. You wouldn't be able to prevent that even when using an functional language, if it had pointers.
And on a side note - why are you trying to force yourself in using C++ in a functional manner? I can understand it's simpler for you, and you're used to it, but functional programming isn't often used because of its downfalls. Note that whenever you create a new object, you have to allocate space. It's slower for the end-user.
Bartoz Milewski has implemented Okasaki's functional data structures in C++. He gives a very thorough treatise on why functional data structures are important for concurrency. In that treatise, he explains the need in concurrency to construct an object and then afterwards make it immutable:
Here’s what needs to happen: A thread has to somehow construct the
data that it destined to be immutable. Depending on the structure of
that data, this could be a very simple or a very complex process. Then
the state of that data has to be frozen — no more changes are
allowed.
As others have said, when you want to expose data in C++ and have it not be available for changing, you make your function signature look like this:
class MutableButExposesImmutably
{
private:
std::string member;
public:
void complicatedProcess() { member = "something else"; } // mutates
const std::string & immutableAccessToMember() const {
return member;
}
};
This is an example of a data structure that is mutable, but you can't mutate it directly.
I think what you are looking for is something like java's final keyword: This keyword allows you to construct an object, but thereafter the object remains immutable.
You can do this in C++. The following code sample compiles. Note that in the class Immutable, the object member is literally immutable, (unlike what it was in the previous example): You can construct it, but once constructed, it is immutable.
#include <iostream>
#include <string>
using namespace std;
class Immutable
{
private:
const std::string member;
public:
Immutable(std::string a) : member(a) {}
const std::string & immutable_member_view() const { return member; }
};
int main() {
Immutable foo("bar");
// your code goes here
return 0;
}
Re. your code example with s and t. You can do this in C++, but "immutability" has nothing to do with that question, if I understand your requirements correctly!
I have used containers in vendor libraries that do operate the way you describe; i.e. when they are copied they share their internal data, and they don't make a copy of the internal data until it's time to change one of them.
Note that in your code example, there is a requirement that if s changes then t must not change. So s has to contain some sort of flag or reference count to indicate that t is currently sharing its data, so when s has its data changed, it needs to split off a copy instead of just updating its data.
So, as a very broad outline of what your container will look like: it will consist of a handle (e.g. a pointer) to some data, plus a reference count; and your functions that update the data all need to check the refcount to decide whether to reallocate the data or not; and your copy-constructor and copy-assignment operator need to increment the refcount.
I have a simple container class with a copy constructor.
Do you recommend using getters and setters, or accessing the member variables directly?
public Container
{
public:
Container() {}
Container(const Container& cont) //option 1
{
SetMyString(cont.GetMyString());
}
//OR
Container(const Container& cont) //option 2
{
m_str1 = cont.m_str1;
}
public string GetMyString() { return m_str1;}
public void SetMyString(string str) { m_str1 = str;}
private:
string m_str1;
}
In the example, all code is inline, but in our real code there is no inline code.
Update (29 Sept 09):
Some of these answers are well written however they seem to get missing the point of this question:
this is simple contrived example to discuss using getters/setters vs variables
initializer lists or private validator functions are not really part of this question. I'm wondering if either design will make the code easier to maintain and expand.
Some ppl are focusing on the string in this example however it is just an example, imagine it is a different object instead.
I'm not concerned about performance. we're not programming on the PDP-11
EDIT: Answering the edited question :)
this is simple contrived example to
discuss using getters/setters vs
variables
If you have a simple collection of variables, that don't need any kind of validation, nor additional processing then you might consider using a POD instead. From Stroustrup's FAQ:
A well-designed class presents a clean
and simple interface to its users,
hiding its representation and saving
its users from having to know about
that representation. If the
representation shouldn't be hidden -
say, because users should be able to
change any data member any way they
like - you can think of that class as
"just a plain old data structure"
In short, this is not JAVA. you shouldn't write plain getters/setters because they are as bad as exposing the variables them selves.
initializer lists or private validator functions are not really
part of this question. I'm wondering
if either design will make the code
easier to maintain and expand.
If you are copying another object's variables, then the source object should be in a valid state. How did the ill formed source object got constructed in the first place?! Shouldn't constructors do the job of validation? aren't the modifying member functions responsible of maintaining the class invariant by validating input? Why would you validate a "valid" object in a copy constructor?
I'm not concerned about performance. we're not programming on the PDP-11
This is about the most elegant style, though in C++ the most elegant code has the best performance characteristics usually.
You should use an initializer list. In your code, m_str1 is default constructed then assigned a new value. Your code could be something like this:
class Container
{
public:
Container() {}
Container(const Container& cont) : m_str1(cont.m_str1)
{ }
string GetMyString() { return m_str1;}
void SetMyString(string str) { m_str1 = str;}
private:
string m_str1;
};
#cbrulak You shouldn't IMO validate cont.m_str1 in the copy constructor. What I do, is to validate things in constructors. Validation in copy constructor means you you are copying an ill formed object in the first place, for example:
Container(const string& str) : m_str1(str)
{
if(!valid(m_str1)) // valid() is a function to check your input
{
// throw an exception!
}
}
You should use an initializer list, and then the question becomes meaningless, as in:
Container(const Container& rhs)
: m_str1(rhs.m_str1)
{}
There's a great section in Matthew Wilson's Imperfect C++ that explains all about Member Initializer Lists, and about how you can use them in combination with const and/or references to make your code safer.
Edit: an example showing validation and const:
class Container
{
public:
Container(const string& str)
: m_str1(validate_string(str))
{}
private:
static const string& validate_string(const string& str)
{
if(str.empty())
{
throw runtime_error("invalid argument");
}
return str;
}
private:
const string m_str1;
};
As it's written right now (with no qualification of the input or output) your getter and setter (accessor and mutator, if you prefer) are accomplishing absolutely nothing, so you might as well just make the string public and be done with it.
If the real code really does qualify the string, then chances are pretty good that what you're dealing with isn't properly a string at all -- instead, it's just something that looks a lot like a string. What you're really doing in this case is abusing the type system, sort of exposing a string, when the real type is only something a bit like a string. You're then providing the setter to try to enforce whatever restrictions the real type has compared to a real string.
When you look at it from that direction, the answer becomes fairly obvious: rather than a string, with a setter to make the string act like some other (more restricted) type, what you should be doing instead is defining an actual class for the type you really want. Having defined that class correctly, you make an instance of it public. If (as seems to be the case here) it's reasonable to assign it a value that starts out as a string, then that class should contain an assignment operator that takes a string as an argument. If (as also seems to be the case here) it's reasonable to convert that type to a string under some circumstances, it can also include cast operator that produces a string as the result.
This gives a real improvement over using a setter and getter in a surrounding class. First and foremost, when you put those in a surrounding class, it's easy for code inside that class to bypass the getter/setter, losing enforcement of whatever the setter was supposed to enforce. Second, it maintains a normal-looking notation. Using a getter and a setter forces you to write code that's just plain ugly and hard to read.
One of the major strengths of a string class in C++ is using operator overloading so you can replace something like:
strcpy(strcat(filename, ".ext"));
with:
filename += ".ext";
to improve readability. But look what happens if that string is part of a class that forces us to go through a getter and setter:
some_object.setfilename(some_object.getfilename()+".ext");
If anything, the C code is actually more readable than this mess. On the other hand, consider what happens if we do the job right, with a public object of a class that defines an operator string and operator=:
some_object.filename += ".ext";
Nice, simple and readable, just like it should be. Better still, if we need to enforce something about the string, we can inspect only that small class, we really only have to look one or two specific, well-known places (operator=, possibly a ctor or two for that class) to know that it's always enforced -- a totally different story from when we're using a setter to try to do the job.
Do you anticipate how the string is returned, eg. white space trimmed, null checked, etc.? Same with SetMyString(), if the answer is yes, you are better off with access methods since you don't have to change your code in zillion places but just modify those getter and setter methods.
Ask yourself what the costs and benefits are.
Cost: higher runtime overhead. Calling virtual functions in ctors is a bad idea, but setters and getters are unlikely to be virtual.
Benefits: if the setter/getter does something complicated, you're not repeating code; if it does something unintuitive, you're not forgetting to do that.
The cost/benefit ratio will differ for different classes. Once you're ascertained that ratio, use your judgment. For immutable classes, of course, you don't have setters, and you don't need getters (as const members and references can be public as no one can change/reseat them).
There's no silver bullet as how to write the copy constructor.
If your class only has members which provide a copy constructor that creates
instances which do not share state (or at least do not appear to do so) using an initializer list is a good way.
Otherwise you'll have to actually think.
struct alpha {
beta* m_beta;
alpha() : m_beta(new beta()) {}
~alpha() { delete m_beta; }
alpha(const alpha& a) {
// need to copy? or do you have a shared state? copy on write?
m_beta = new beta(*a.m_beta);
// wrong
m_beta = a.m_beta;
}
Note that you can get around the potential segfault by using smart_ptr - but you can have a lot of fun debugging the resulting bugs.
Of course it can get even funnier.
Members which are created on demand.
new beta(a.beta) is wrong in case you somehow introduce polymorphism.
... a screw the otherwise - please always think when writing a copy constructor.
Why do you need getters and setters at all?
Simple :) - They preserve invariants - i.e. guarantees your class makes, such as "MyString always has an even number of characters".
If implemented as intended, your object is always in a valid state - so a memberwise copy can very well copy the members directly without fear of breaking any guarantee. There is no advantage of passing already validated state through another round of state validation.
As AraK said, the best would be using an initializer list.
Not so simple (1):
Another reason to use getters/setters is not relying on implementation details. That's a strange idea for a copy CTor, when changing such implementation details you almost always need to adjust CDA anyway.
Not so simple (2):
To prove me wrong, you can construct invariants that are dependent on the instance itself, or another external factor. One (very contrieved) example: "if the number of instances is even, the string length is even, otherwise it's odd." In that case, the copy CTor would have to throw, or adjust the string. In such a case it might help to use setters/getters - but that's not the general cas. You shouldn't derive general rules from oddities.
I prefer using an interface for outer classes to access the data, in case you want to change the way it's retrieved. However, when you're within the scope of the class and want to replicate the internal state of the copied value, I'd go with data members directly.
Not to mention that you'll probably save a few function calls if the getter are not inlined.
If your getters are (inline and) not virtual, there's no pluses nor minuses in using them wrt direct member access -- it just looks goofy to me in terms of style, but, no big deal either way.
If your getters are virtual, then there is overhead... but nevertheless that's exactly when you DO want to call them, just in case they're overridden in a subclass!-)
There is a simple test that works for many design questions, this one included: add side-effects and see what breaks.
Suppose setter not only assigns a value, but also writes audit record, logs a message or raises an event. Do you want this happen for every property when copying object? Probably not - so calling setters in constructor is logically wrong (even if setters are in fact just assignments).
Although I agree with other posters that there are many entry-level C++ "no-no's" in your sample, putting that to the side and answering your question directly:
In practice, I tend to make many but not all of my member fields* public to start with, and then move them to get/set when needed.
Now, I will be the first to say that this is not necessarily a recommended practice, and many practitioners will abhor this and say that every field should have setters/getters.
Maybe. But I find that in practice this isn't always necessary. Granted, it causes pain later when I change a field from public to a getter, and sometimes when I know what usage a class will have, I give it set/get and make the field protected or private from the start.
YMMV
RF
you call fields "variables" - I encourage you to use that term only for local variables within a function/method
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
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...
}