I'm trying to figure out when const should be used when writing C++ code. Are these all examples of pessimization or is it beneficial to write code this way?:
Example 1:
int findVal(const int OTHER_VAL) const
{
switch(OTHER_VAL)
{
case 1:
return 2;
default:
return 3;
}
}
Example 2:
enum class MobType
{
COW, CHICKEN, DOG, PIG
};
class BaseMob
{
protected:
BaseMob(const MobType TYPE) : TYPE(TYPE) { }
const MobType TYPE;
};
Example 3:
void showWorld(const World &world)
{
auto data = world.getData();
for (auto &i:data)
i.print();
}
No, they aren't.
const on local variables with automatic storage (including function args) is purely syntactic sugar to help human programmers set rules for their code. It doesn't help the optimizer at all. Optimizing compilers extract the necessary data-movement from the C source, and optimize that. They generally don't care if you reuse the same tmp variable for many different things, or have 10 different const tmp1 = a+10; in the same function.
And yes, this applies to function args passed by value; they are local variables with automatic storage, passed in registers or on the stack. And no, this doesn't mean the caller can assume that a function didn't modify the stack memory used for arg-passing, so it doesn't help the optimizer much either. (Making a 2nd function call with the same arguments still requires re-writing the args to the stack (if not all args fit in registers), because the const on an arg doesn't change the fact that the called function "owns" that stack space and can use it as scratch space however it wants.)
const on static/global/reference variables does help. static const int foo = 10; can be inlined as an immediate constant instead of loaded from memory. (e.g. add eax, 10 instead of add eax, [foo]).
Using const to mark a class method as not changing any class members can also help the compiler avoid re-loading class members after a function call. (i.e. keep them live in registers). This mostly only applies if the compiler can't see the function definition, otherwise a good optimizing compiler can just look at what the called function does and optimize accordingly. (As long as it's not in a Unix library, where symbol interposition means that it can't assume the called function it sees at compile time will be the one called after dynamic linking.)
Whenever you logically do not alter a value or an object you should make it const. By logically I do not mean every time you are technically allowed to, but every time it is logical in the context of your functions, classes and code.
A simple example could be a simple "get" function as seen in example 1, these functions should not modify the state of the class, and should therefore be marked constant, as this will help document your intent to the user, besides helping you ensure the invariance of the class.
There are situations where it makes sense to make an immutable object, as seen in example 2. It is not that often we see these in C++, but many other languages use them frequently. If it does not add any value to be able to change a certain member during an objects lifetime, you might as well make it const.
Passing const reference parameters gives you the performance benefits of the reference, but at the same time ensures that the source object is kept unmodified, which is both great documentation to the user, but also allows som optimizations to happen.
Having mentioned all these reasons, there are other reasons to use const as briefly mentioned in the last paragraph, optimizations. When the compiler knows that something is constant and is not being altered it can enable some pretty clever optimizations, don't use const for performance reasons though.
This is also why working around constness by (for instance) the const_cast cast, which can cast away const, can lead to some undesired behaviour. As an example check out the following:
#include <stdio.h>
static const int foo = 10;
int constsum(void) {
return foo + 5;
}
int main(int argc, char* argv[]) {
int a = constsum();
int* newFoo = const_cast<int*>(&foo);
*newFoo = 20;
int b = constsum();
printf("%d\n", a + b);
return 0;
}
As can be seen from this example (see code running here) this might not produce the desired result, as the code result in 30 being printed, and not as perhaps expected 40.
When examining the produced assembly we can see why (compiled into assembly):
constsum():
mov eax, 15
ret
main:
mov eax, 30
ret
The compiler simply inlines the values, as it can see that they constant, it does not take special care that the const_cast is being used.
So const correctness, and use of const is a valuable tool, that can benefit performance, and stability of your code, but also (and not to forget) it helps documenting your code.
Related
When learning C++, one of the first functions one gets for learning the concept of a function is something like
int add(int a, int b)
{
return a+b;
}
Now I was wondering: Should I use the const-keyword here, or rather not, resulting in
int add(const int a, const int b)
{
return a+b;
}
But would that make sense? Would it speed my program up, do some other important stuff, or just increase confusion?
From the caller's perspective, both the first and the second form are the same.
Since the integers are passed by value, even if the function modifies a and b, the modified values are copies of the original and won't be visible to the caller.
However, from the function implementer's perspective there's a difference. In fact, in the second form:
int add(const int a, const int b)
you will get a compiler error if you try to modify the values of a and b inside the function's body, as they are marked as const.
Instead, you can change those values if you omit the const.
Again, those modifications will not be visible to the caller.
If you are actually struggling with correctness bugs in your codebase where const would have helped, then add const.
That said, there are related issues that you should consider. Top-level qualifiers of function parameters aren't part of the function type, so your function type is still just int(int, int). (The qualifiers only affect the parameter variables in the function definition.) That means that any declaration of the function also ignores qualifiers, so int add(int, int) and int add(const int, int) and int add(int, const int) all declare the same function. So you have to decide on a policy for how you write header files. And now you have three essential positions you can take:
Always qualify in both declaration and definition. The upside is that this perhaps keeps code looking "consistent" (think copy/pasting when creating implementations). The downside is that the qualifiers have nothing to do with the interface, and are not at all enforcible (you can change the definition later!), so at best it's noise, at worst it's wrong.
Qualify in the definition, but not in the other declarations. The upside is that this communicates the interface correctly and you still get const checking in the definition. The downside is that some people might be confused by the discrepancies in spelling. (Just like people may be confused that a static constexpr T foo; class member can be defined with const T C::foo;.)
Don't qualify either. The upside is that it's consistent, clean, easy to remember and minimal. The downside is that you're missing out on correctness checks in your definition.
There's no right answer. If you're the codebase owner or project lead, you should decide based on what the biggest problems in your codebase and team are. (My personal position is to stick with (3) until you have a good reason to change.)
Using int add(const int a, const int b) means that you cannot modify the input parameters within the function body.
Perhaps the compiler can make some optimisations based on that, so it ought therefore to be never slower than the non-const equivalent. But I have never observed this effect in practice.
Passing const parameters can also increase the stability of your code base, particularly in a collaborative project.
All this said though, I find it too verbose, rather unnecessary, and would use int add(int a, int b). Very occasionally, for particularly long functions, I exploit the fact that you can declare the function with non-const parameters, and define it with the parameters const.
I feel like everyone is dancing around this part of the answer...
It's true that using const will keep the function from modifying the value of your int a & b while inside the function. This can be extremely useful, so use it as you wish, of the compiler allows it. But, the function caller will never know about any changes to a & b once the function finishes. So even if a & b are changed, no one except the defined function will know their updated values.
int funcB(int a, int b)
{
a = a+1;
b = b*b;
return a+b;
}
void funcA()
{
int s = 5;
int t = 6;
int result = funcB(s, t);
printf("%f + %f = %f", s,t, result);
}
funcA prints: "5 + 6 = 42"
Const protection is often used when passing values by reference, ie:
int function(const int &a, const int &b) {}
This passes a reference of a and b to the function (ie, does not make copies of a and b but passes only a memory address of that variable, aka: the handle). When passing a variable by reference, any changes made to the variable are remembered outside the scope of the function and can change the way your program runs. This is generally undesired behavior.
So if you rework funcB from above and pass by reference:
int funcB(int &a, int &b)
{
a = a+1;
b = b*b;
return a+b;
}
funcA prints: "6 + 36 = 42"
If you add const correctness to funcB:
int funcB(const int &a, const int &b)
{
a = a+1;
b = b*b;
return a+b;
}
I don't think the compiler will let you even do this since you would be explicitly trying to modify values that you've protected via const.
Another time when it may be really important to use const is when you're passing by pointer, instead of reference or copy...
int funcB(int *a, int *b)
{
a = a+1;
b = b*b;
return a+b;
}
Unless you're a pointer expert, avoid passing pointers without const pretention. This func will likely attempt to iterate the index of your pointer arrays and you'd open yourself up to run time errors related to out of bound memory. You could accidently see memory from an entirely different program... but probably not.
Lastly, since you're just passing int, there's no practical need to pass by reference (which is done often to keep from adding complex data into memory because each non-reference or non-pointer pass to functions copies the value into memory for the life of the function being called) since the memory footprint of int is so small. Unless, you're working with specialized hardware that has extremely limited memory, then it may be useful; this won't apply to most standard computers and desktops made within the past 20 years, or smart phones.
int add(const int a, const int b)
{
return a+b;
}
Here const in used so that the function does not modify the original values of a and b by any chance.
In the above example it does not make sense. But if it would have been an example like
int add(const int *a, const int *b)
{
//*a = 10; //This will throw error.
return a+b;
}
In functions where objects,arrays or such data types are passed its a good approach to use const to avoid mutation of original data structure.
If you want to be truly const correct, then you should add it, but in reality all it will do is make you type and read more.
Nothing will go faster, and while it could mean that your variables go into another location in memory, it's unlikely to on most modern machines.
What it will stop you doing is accidentally assigning them values, but as they're local to the function, it's relatively unimportant. What would matter is if they were references, as this demonstrates your intent to the caller to not change them.
You can use const there if you like.
It is unlikely to speed up your program because any reasonable compiler can already see that no code path alters the value of a or b and make any optimisations it needs.
a and b are int, which are passed by value so making them const has no impact on the users of this function.
The only possible advantage is where your function is long and more complex and you want to avoid possible programming errors where the original values of a or b are changed during the function.
If you will use const then you cannot modify the value of a,b. Thats why we don't use const.
The primary purpose of constness is to provide documentation and prevent programming mistakes. Const allows you to make it clear to yourself and others that something should not be changed. Moreover, it has the added benefit that anything that you declare const will in fact remain const short of the use of forceful methods. It's particularly useful to declare reference parameters to functions as const references:
bool SomeFunction (const myObj& obj);
Here, a myObj object is passed by reference into SomeFunction. For safety's sake, const is used to ensure that SomeFunction cannot change the object--after all, it's just supposed to make sure that the object is in a valid state. This can prevent silly programming mistakes that might otherwise result in damaging the object (for instance, by setting a field of the class for testing purposes, which might result in the field's never being reset). Moreover, by declaring the argument const, users of the function can be sure that their object will not be changed and not need to worry about the possible side effects of making the function call.
moreover, The reason is that const for the parameter only applies locally within the function, since it is working on a copy of the data. This means the function signature is really the same anyways. It's probably bad style to do this a lot though. I personally tend to not use const except for reference and pointer parameters.
as a law of thumb we are advised to use const as much as possible because we get a great help from the compiler so whenever we try to change a constant the mistake will be caught by the compiler; it's a good thing avoiding being caught in error-prones.
the second thing: a and b passed by value so they are created as local constants But as long as they are not changeable why we need copies??
the good thing is to pass a const reference which means never change parameters and avoid copies (by value):
int add(const int& a, const int& b) // now there are no copies of a and b in addition we cannot modify a and be
{
return a+b;
}
The main portion of this question is in regards to the proper and most computationally efficient method of creating a public read-only accessor for a private data member inside of a class. Specifically, utilizing a const type & reference to access the variables such as:
class MyClassReference
{
private:
int myPrivateInteger;
public:
const int & myIntegerAccessor;
// Assign myPrivateInteger to the constant accessor.
MyClassReference() : myIntegerAccessor(myPrivateInteger) {}
};
However, the current established method for solving this problem is to utilize a constant "getter" function as seen below:
class MyClassGetter
{
private:
int myPrivateInteger;
public:
int getMyInteger() const { return myPrivateInteger; }
};
The necessity (or lack thereof) for "getters/setters" has already been hashed out time and again on questions such as: Conventions for accessor methods (getters and setters) in C++ That however is not the issue at hand.
Both of these methods offer the same functionality using the syntax:
MyClassGetter a;
MyClassReference b;
int SomeValue = 5;
int A_i = a.getMyInteger(); // Allowed.
a.getMyInteger() = SomeValue; // Not allowed.
int B_i = b.myIntegerAccessor; // Allowed.
b.myIntegerAccessor = SomeValue; // Not allowed.
After discovering this, and finding nothing on the internet concerning it, I asked several of my mentors and professors for which is appropriate and what are the relative advantages/disadvantages of each. However, all responses I received fell nicely into two categories:
I have never even thought of that, but use a "getter" method as it is "Established Practice".
They function the same (They both run with the same efficiency), but use a "getter" method as it is "Established Practice".
While both of these answers were reasonable, as they both failed to explain the "why" I was left unsatisfied and decided to investigate this issue further. While I conducted several tests such as average character usage (they are roughly the same), average typing time (again roughly the same), one test showed an extreme discrepancy between these two methods. This was a run-time test for calling the accessor, and assigning it to an integer. Without any -OX flags (In debug mode), the MyClassReference performed roughly 15% faster. However, once a -OX flag was added, in addition to performing much faster both methods ran with the same efficiency.
My question is thus has two parts.
How do these two methods differ, and what causes one to be faster/slower than the others only with certain optimization flags?
Why is it that established practice is to use a constant "getter" function, while using a constant reference is rarely known let alone utilized?
As comments pointed out, my benchmark testing was flawed, and irrelevant to the matter at hand. However, for context it can be located in the revision history.
The answer to question #2 is that sometimes, you might want to change class internals. If you made all your attributes public, they're part of the interface, so even if you come up with a better implementation that doesn't need them (say, it can recompute the value on the fly quickly and shave the size of each instance so programs that make 100 million of them now use 400-800 MB less memory), you can't remove it without breaking dependent code.
With optimization turned on, the getter function should be indistinguishable from direct member access when the code for the getter is just a direct member access anyway. But if you ever want to change how the value is derived to remove the member variable and compute the value on the fly, you can change the getter implementation without changing the public interface (a recompile would fix up existing code using the API without code changes on their end), because a function isn't limited in the way a variable is.
There are semantic/behavioral differences that are far more significant than your (broken) benchmarks.
Copy semantics are broken
A live example:
#include <iostream>
class Broken {
public:
Broken(int i): read_only(read_write), read_write(i) {}
int const& read_only;
void set(int i) { read_write = i; }
private:
int read_write;
};
int main() {
Broken original(5);
Broken copy(original);
std::cout << copy.read_only << "\n";
original.set(42);
std::cout << copy.read_only << "\n";
return 0;
}
Yields:
5
42
The problem is that when doing a copy, copy.read_only points to original.read_write. This may lead to dangling references (and crashes).
This can be fixed by writing your own copy constructor, but it is painful.
Assignment is broken
A reference cannot be reseated (you can alter the content of its referee but not switch it to another referee), leading to:
int main() {
Broken original(5);
Broken copy(4);
copy = original;
std::cout << copy.read_only << "\n";
original.set(42);
std::cout << copy.read_only << "\n";
return 0;
}
generating an error:
prog.cpp: In function 'int main()':
prog.cpp:18:7: error: use of deleted function 'Broken& Broken::operator=(const Broken&)'
copy = original;
^
prog.cpp:3:7: note: 'Broken& Broken::operator=(const Broken&)' is implicitly deleted because the default definition would be ill-formed:
class Broken {
^
prog.cpp:3:7: error: non-static reference member 'const int& Broken::read_only', can't use default assignment operator
This can be fixed by writing your own copy constructor, but it is painful.
Unless you fix it, Broken can only be used in very restricted ways; you may never manage to put it inside a std::vector for example.
Increased coupling
Giving away a reference to your internals increases coupling. You leak an implementation detail (the fact that you are using an int and not a short, long or long long).
With a getter returning a value, you can switch the internal representation to another type, or even elide the member and compute it on the fly.
This is only significant if the interface is exposed to clients expecting binary/source-level compatibility; if the class is only used internally and you can afford to change all users if it changes, then this is not an issue.
Now that semantics are out of the way, we can speak about performance differences.
Increased object size
While references can sometimes be elided, it is unlikely to ever happen here. This means that each reference member will increase the size of an object by at least sizeof(void*), plus potentially some padding for alignment.
The original class MyClassA has a size of 4 on x86 or x86-64 platforms with mainstream compilers.
The Broken class has a size of 8 on x86 and 16 on x86-64 platforms (the latter because of padding, as pointers are aligned on 8-bytes boundaries).
An increased size can bust up CPU caches, with a large number of items you may quickly experience slow downs due to it (well, not that it'll be easy to have vectors of Broken due to its broken assignment operator).
Better performance in debug
As long as the implementation of the getter is inline in the class definition, then the compiler will strip the getter whenever you compile with a sufficient level of optimizations (-O2 or -O3 generally, -O1 may not enable inlining to preserve stack traces).
Thus, the performance of access should only vary in debug code, where performance is least necessary (and otherwise so crippled by plenty of other factors that it matters little).
In the end, use a getter. It's established convention for a good number of reasons :)
When implementing constant reference (or constant pointer) your object also stores a pointer, which makes it bigger in size. Accessor methods, on the other hand, are instantiated only once in program and are most likely optimized out (inlined), unless they are virtual or part of exported interface.
By the way, getter method can also be virtual.
To answer question 2:
const_cast<int&>(mcb.myIntegerAccessor) = 4;
Is a pretty good reason to hide it behind a getter function. It is a clever way to do a getter-like operation, but it completely breaks abstraction in the class.
As far as I know , making constant functions in a class is useful for read/write compiler optimizations.
A constant function within a class means that the class members will remain constant during the execution of the function.
However, you can bypass this by const casting the implicit parameter (ofc this is a very bad practice).
My questions is as follows :
What pitfalls can the following code cause (especially in terms of performance unrelated to thread synchronization) ?
int myClass::getSomething() const
{
myClass* writableThis = const_cast<myClass*>(this);
writableThis->m_nMemberInt++;
...
return m_nSomeOtherUnchangedMember;
}
Another related question :
Is the behavior compiler/platform/os specific ?
I would also very much appreciate if someone could explain the magic under the hood when such a code is compiled/executed (I'm speculating that the CPU is making out-of-order optimizations based on the fact that the function is const , and not respecting this during actual execution should have some side effects).
EDIT :
Thank you for clarifying this for me. After further research all the received answers are correct but I can accept only one :).
Regarding the const qualifier being used solely for syntax corectness , I believe this answer is both right and wrong, the correct way to state this (imho) would be that it is used mostly for syntax corectness (in a very limited number of scenarios it can produce different / better code ). References : SO Related question , related article
The const_cast<T>(this) trick is potentially unsafe, because the user of your member function may run into undefined behavior without doing anything wrong on their side.
The problem is that casting away const-ness is allowed only when you start with a non-const object. If your object is constant, the function that casts away its const-ness and uses the resultant pointer to change object's state triggers undefined behavior:
struct Test {
int n;
Test() : n(0) {}
void potentiallyUndefinedBehavior() const {
Test *wrong = const_cast<Test*>(this);
wrong->n++;
}
};
int main() {
Test t1;
// This call is OK, because t1 is non-const
t1.potentiallyUndefinedBehavior();
const Test t2;
// This triggers undefined behavior, because t2 is const
t2.potentiallyUndefinedBehavior();
return 0;
}
The trick with const_cast<T>(this) has been invented for caching values inside member functions with const qualifier. However, it is no longer useful, because C++ added a special keyword for this sort of things: by marking a member mutable you make that member writable inside const-qualified methods:
struct Test {
mutable int n;
Test() : n(0) {}
void wellDefinedBehavior() const {
n++;
}
};
Now the const member function will not trigger undefined behavior regardless of the context.
The CPU doesn't know anything about const, which is a C++ keyword. By the time the compiler has transformed the C++ code to assembly, there's not much left of that.
Of course, there's a real possibility that the generated code is entirely different because of the const keyword. For instance, the const version of some operator[] may return a T object by value whereas the non-const version must return a T&. A CPU doesn't even know what function it's in, or even assume the existence of functions.
My answer is to use the storage class mutable for any thing which need to be modified in const methods.
It's built into the language, so there are several benefits. It's a tighter control for how const methods modify data members. Other developers will know these data members will change in const methods. If there are any compiler optimizations, the compiler will know to do the right thing.
class myClass {
private:
int m_nSomeOtherUnchangedMember;
mutable int m_nMemberInt;
…
public:
int getSomething() const;
…
};
int myClass::getSomething() const
{
m_nMemberInt++;
…
return m_nSomeOtherUnchangedMember;
}
As far as I know , making constant functions in a class is useful for read/write compiler optimizations.
No. We use const methods to enforce semantic guarantees, not to allow optimizations (with the possible exception of avoiding copies).
What pitfalls can the following code cause
Firstly, it can break program semantics.
For example, std::map nodes store std::pair<const Key, T>, because the Key shouldn't mutate after it has been inserted. If the key changes value, the map sorting invariant is incorrect, and subsequent find/insert/rebalance operations will misbehave.
If you call a const-qualified method on this const key, and that method changes the Key in a way that affects how it compares, then you've cunningly broken the map.
Secondly, it can kill your program. If you have a const object overlaid on a genuinely read-only address range, or you have a statically-initialized const object in the read-only initialized data segment, then writing to it will cause some kind of protection error
As other stated the const-correctness was designed as a help for the programmers and not an help for the optimizer. You should remember 4 things:
1. const references and const methods are not faster
2. const references and const methods are not faster
3. const references and const methods are not faster
4. const references and const methods are not faster
More specifically the optimizer simply completely ignores const-ness of references or of methods because const doesn't really mean in that context what you are thinking.
A const reference to an object doesn't mean that for example during the execution of a method the object will remain constant. Consider for example:
struct MyObject {
int x;
void foo() const {
printf("%i\n", x);
char *p = new char[10];
printf("%i\n", x);
delete[] p;
}
};
the compiler cannot assume that x member didn't mutate between the two calls to printf. The reason is that std::operator new global allocator could have been overloaded and the code could have regular non-const pointer to the instance. Therefore it's perfectly legal for the global allocator to change x during the execution of foo. The compiler cannot know this is not going to happen (the global allocator could be overloaded in another
compilation unit).
Calling any unknown code (i.e. basically any non-inlined function) can mutate any part of an object, being in a const method or not. The const method simply means that you cannot use this to mutate the object, not that the object is constant.
If const correctness is really an help for the programmers is another question on which I personally have a quite heretic point of view, but that's another story...
I need a once-and-for-all clarification on passing by value/pointer/reference.
If I have a variable such as
int SomeInt = 10;
And I want to pass it to a function like
void DoSomething(int Integer)
{
Integer = 1;
}
In my current scenario when passing SomeInt to DoSomething() I want SomeInt's value to be updated based on whatever we do to it inside of DoSomething() as well as be most efficient on memory and performance so I'm not copying the variable around?. That being said which of the following prototypes would accomplish this task?
void DoSomething(int* Integer);
void DoSomething(int& Integer);
How would I actually pass the variable into the function? What is the difference between the previous two prototypes?
Finally if using a function within a class
class SomeClass
{
int MyInteger;
public:
void ChangeValue(int& NewValue)
{
MyInteger = NewValue;
}
};
If I pass an integer into ChangeValue, when the integer I passed in get's deleted will that mean when I try to use MyInteger from within the class it will no longer be useable?
Thank you all for your time, I know this is kind of a basic question but the explanations I keep running into confuse me further.
Functionally, all three of these work:
pass an int and change the return type to int so you can return the new value, usage: x = f(x);
when you plan to set the value without needing to read the initial value, it's much better to use a function like int DoSomething(); so the caller can just say int x = f(); without having to create x on an earlier line and wondering/worrying whether it needs to be initialised to anything before the call.
pass an int& and set it inside the function, usage: int x; x = ? /* if an input */; f(x);
pass an int* and set the pointed-to int inside the function, usage: int x; x = ?; f(&x);
most efficient on memory and performance so I'm not copying the variable around
Given the C++ Standard doesn't dictate how references should be implemented by the compiler, it's a bit dubious trying to reason about their characteristics - if you care compile your code to assembly or machine code and see how it works out on your particular compiler (for specific compiler commandline options etc.). If you need a rule of thumb, assume that references have identical performance characteristics to pointers unless profiling or generated-code inspection suggests otherwise.
For an int you can expect the first version above to be no slower than the pointer version, and possibly be faster, because the int parameter can be passed and returned in a register without ever needing a memory address.
If/when/where the by-pointer version is inlined there's more chance that the potentially slow "needing a memory address so we can pass a pointer" / "having to dereference a pointer to access/update the value" aspect of the pass-by-pointer version can be optimised out (if you've asked the compiler to try), leaving both versions with identical performance....
Still, if you need to ask a question like this I can't imagine you're writing code where these are the important optimisation choices, so a better aim is to do what gives you the cleanest, most intuitive and robust usage for the client code... now - whether that's x = f(x); (where you might forget the leading x =), or f(x) where you might not realise x could be modified, or f(&x) (where some caller might think they can pass nullptr is a reasonable question in its own right, but separate from your performance concerns. FWIW, the C++ FAQ Lite recommends references over pointers for this kind of situation, but I personally reject its reasoning and conclusions - it all boils down to familiarity with either convention, and how often you need to pass const pointer values, or pointer values where nullptr is a valid sentinel, that could be confused with the you-may-modify-me implication hoped for in your scenario... that depends a lot on your coding style, libraries you use, problem domain etc..
Both of your examples
void DoSomething(int* Integer);
void DoSomething(int& Integer);
will accomplish the task. In the first case - with pointer - you need to call the function with DoSomething(&SomeInt);, in the second case - with reference - simpler as DoSomething(SomeInt);
The recommended way is to use references whenever they are sufficient, and pointers only if they are necessary.
You can use either. Function call for first prototype would be
DoSomething(&SomeInt);
and for second prototype
DoSomething(SomeInt);
As was already said before, you can use both. The advantage of the
void DoSomething(int* Integer)
{
*Integer=0xDEADBEEF;
}
DoSomething(&myvariable);
pattern is that it becomes obvious from the call that myvariable is subject to change.
The advantage of the
void DoSomething(int& Integer)
{
Integer=0xDEADBEEF;
}
DoSomething(myvariable);
pattern is that the code in DoSomething is a bit cleaner, DoSomething has a harder time to mess with memory in bad ways and that you might get better code out of it. Disadvantage is that it isn't immediately obvious from reading the call that myvariable might get changed.
In a project I maintain, I see a lot of code like this for simple get/set methods
const int & MyClass::getFoo() { return m_foo; }
void MyClass::setFoo(const int & foo) { m_foo = foo; }
What is the point in doing that instead of the following?
int MyClass::getFoo() { return m_foo; } // Removed 'const' and '&'
void MyClass::setFoo(const int foo) { m_foo = foo; } // Removed '&'
Passing a reference to a primitive type should require the same (or more) effort as passing the type's value itself, right?
It's just a number after all...
Is this just some attempted micro-optimization or is there a true benefit?
The difference is that if you get that result into a reference yourself you can track the changes of the integer member variable in your own variable name without recalling the function.
const &int x = myObject.getFoo();
cout<<x<<endl;
//...
cout<<x<<endl;//x might have changed
It's probably not the best design choice, and it's very dangerous to return a reference (const or not), in case a variable that gets freed from scope is returned. So if you return a reference, be careful to be sure it is not a variable that goes out of scope.
There is a slight difference for the modifier too, but again probably not something that is worth doing or that was intended.
void test1(int x)
{
cout<<x<<endl;//prints 1
}
void test2(const int &x)
{
cout<<x<<endl;//prints 1 or something else possibly, another thread could have changed x
}
int main(int argc, char**argv)
{
int x = 1;
test1(x);
//...
test2(x);
return 0;
}
So the end result is that you obtain changes even after the parameters are passed.
To me, passing a const reference for primitives is a mistake. Either you need to modify the value, and in that case you pass a non-const reference, or you just need to access the value and in that case you pass a const.
Const references should only be used for complex classes, when copying objects could be a performance problem. In the case of primitives, unless you need to modify the value of the variable you shouldn't pass a reference. The reason is that references take more computation time than non-references, since with references, the program needs to look up in a table to find the address of the object. When this look-up time is shorter than the copying time, references are an improvement.
Generally, ints and addresses have the same byte length in low-level implementations. So the time of copying an int as a return value for a function is equivalent to the time of copying an address. But in the case where an int is returned, no look up is performed, therefore performance is increased.
The main difference between returning a value and returning a const reference is that you then can const_cast that reference and alter the value.
It's an example of bad design and an attempt to create a smart design where easy and concise design would be more than enough. Instead of just returning a value the author makes readers of code think what intention he might have had.
There is not much benefit. I have seen this in framework or macro generated getters and setters before. The macro code did not distinguish between primitive and non-POD types and just used const type& across the board for setters. I doubt that it is an efficiency issue or a genuine misunderstanding; chances are this is a consistency issue.
I think this type of code is written who have misunderstood the concept of references and use it for everything including primitive data types. I've also seen some code like this and can't see any benefit of doing this.
There is no point and benefit except
void MyClass::setFoo(const int foo)
void MyClass::setFoo(const int& foo)
as then you won't be able to reuse 'foo' variable inside 'setFoo' implementation. And I believe that 'int&' is just because Guy just get used to pass all things by const reference and there is nothing wrong with that.