according to some tutorials i read a while back, the "const" declaration makes a variable "constant" ie it cannot change later.
But i find this const declaration abit inconveniencing since the compiler sometimes gives errors like
"cannot convert const int to int"
or something like that.
and i find myself cheating by removing it anyway.
question:
assuming that i am careful about not changing a variable in my source code, can i happily forget about this const stuff?
Thanks in advance
Are you serious? Why would you want to give up on such a useful feature just because you make a mistake sometimes? Better try and learn to avoid mistakes with const and you benefit from the great assistance it adds to ensure correctnes with your code.
Of course, you can say goodbye to all the help the language provides, and tell the compiler thereby not tell you about mistakes in your code anymore. Instead, you will have to ask the debugger later on where your bugs are. Not sure whether that's better.
In C++, "const" can a apply to a variable (making it unchangeable) or a function (rendering it unable to change other things).
My use of "const" is not just to prevent my code from changing my variable. It's to prevent some idiot's code from changing my variable (especially if the idiot is me six months from now) and to prevent my code from changing a critical variable some idiot left exposed (especially if the idiot was me six months ago).
If you are careful, yes. But it is human to err. Also, you do not give the compiler the opportunity to optimize around these constants.
The error message that you get is because you try to alter a const int. Simply assigning the value to a (non-const) int, you alter it as you want to.
Const helps you, try to sprinkle more of it around and listen to the compiler. That will help you produce better code.
Even if you and everyone you work with never makes mistakes, the use of const in your method declarations helps to document your interface.
You lose some useful language features without const, especially regarding references. Consider:
void f(const MyClass& m);
void f(const int& i);
// ...
f(MyClass()); // OK, can pass temporary as const reference
f(5); // OK as well, 5 is a temporary int
If you consider the 'const' optional and get rid of it:
void f(MyClass& m);
void f(int& i);
// ...
f(MyClass()); // Error, cannot pass temporary as non-const reference
f(5); // Error, same as above
The idea behind using 'const' is specifically that you ensure compiler errors when attempting to alter a variable's value when it has been predetermined (by using const) that you do NOT want to do so. It's essentially built in error-checking, and is useful for many reasons.
This is especially valuable in cases such as an external interface and public methods as a way of guaranteeing the caller that a passed value will not be modified.
const also locks in the intent to not modify, and prevents accidental assignment.
While making const use mandatory is unnecessary, it is very useful and good practice.
Here's a useful explanation you may want to check out: http://duramecho.com/ComputerInformation/WhyHowCppConst.html
You can forget about it but isn't it nice if the compiler forces it upon you? That way, your "const" variables actually stay constant.
Its always optional. If its all your code sure you can forget it ( I wouldn't recommend it, because it protects you), but when you interact with others, you're essentially providing a contract for them that you won't change their object or calling a function does not change the state of your object. This can be invaluable when you are not familiar with other's code, or you don't have the source.
To answer your question first:
Yes, you can. But only if you are careful, and everyone else who uses your code from now to eternity is also careful.
So, on balance you are better off thinking about why you should make something const and when you should not.
Another technique for exploring why const makes a difference is to try to make everything const at first until you have valid reasons to change something, then, and only then, remove the minimum number of consts until it works again.
Glad to see you are thinking about the issue - its more than most do.
People usually face this problem when they start using the const keyword. Believe me, it really helps. Leave it to the compiler to take care of the cosntness of the variable, instead of you taking care to not alter its value anywhere.
Changing things that shouldn't be changed is one of the most common sources of error.
It is therefore worthwhile specifying const because it prevents you from doing something wrong. Why would you want to give that up?
const double PI = 3.14159265358979;
PI=4; // generates a compiler error (good)
There are some problems with the c++ notation, because a constant can only be initialized, not assigned the first time, and sometimes, you don't have the value at initialization time.
class A {
private:
const int num;
public:
A(int x, int y) : num(0) { // oops, I don't yet know what num should be
while ( ... ) {
}
num = ...;
}
};
The way out of this one is to define a private function that computes the value of num
but sometimes that means that instead of one clean block of code in the constructor, you are forced to split it into sections in awkward ways, just so you can initialize the variable.
class A {
private:
const int num;
int computeNum(int x, int y) { ... }
public:
A(int x, int y) : num(f(x,y)) {
}
};
Sometimes, you have a value that is generally supposed to be const, but you want to selectively override that when it semantically makes sense. For example, social security numbers don't change, unless your identity is stolen. So you have just one method, called createNewSSN() which changes the otherwise constant ssn
class Person {
private:
const int ssn;
public:
Person(int ssn_) : ssn(ssn_) {}
void createNewSSN(int newssn) {
log << "Changed SSN: " << ssn << " to " << newssn << "\n";
*(int*)&ssn = newssn; // trust me, this is a special case....
}
};
Related
This question already has answers here:
Why should I use reference variables at all? [closed]
(8 answers)
Closed 5 years ago.
I am brand new to C++. We have recently begun exploring reference variables in class, and I am very confused about them. Not necessarily how to do them, as I understand that they switch variable values, but more along the lines of WHY a developer would want to do such a thing? What do they accomplish? Do they save memory? Do they avoid having to return information?
Here is part of the project we are working on. We need to include at least one reference variable. I can see how I would write the program without the reference variable, but I don't see where a reference variable would be useful or necessary.
"The user may wish to get an estimate for one to many rooms. The rates are based on the square footage of the walls and/or ceiling. The company estimates that it takes 2.5 hours to paint 200 SF of wall space and 3.2 hours to paint the same area on a ceiling. The labor rate is $40 per hour. If the job for painting WALLS totals more than 1400 SF of space, then the customer receives a 15% discount for all square footage above 1400 square feet. There is no discount for painting ceilings.
The program shall print out a final report of the estimated costs in a professional format.
The program shall ask the user if they want to make more calculations before exiting."
I'm not looking for you guys to do my homework for me, and for reference, we have only just finished with learning functions. I'm pretty good, but there are a LOT of things reading through these sites that I do not understand.
And, essentially, studentID would be set to 21654. Am I understanding this correctly?
Let us try this again:
I have reviewed this suggested duplication. While it does cover the basics of the pros/cons of using reference variables instead of pointers and discusses multitudes of reasons for using both, I am still questioning the basic idea of when (when is is appropriate vs. not necessary) and why (why is appropriate in certain circumstances, what advantages does it give to the program?)
I should use such variables as well as how (the actual syntax and placement). Almost everyone here has been great, and I have learned so much on the subject through my interactions with you. Even as much of this is repetitive and irritating to seasoned coders, it is all new to me, and I needed to be involved in the conversation as much as I needed the information. I have used Stack Overflow for many projects, learning about Java's newString.equalsIgnoreCase(), for instance, and I admire your knowledge. I can only tell you the truth, if that is not good enough then it is what it is.
Alright, let me review my understanding so far:
Reference variables tend to cut down on unwanted modification of variables within a function and/or program.
Reference variables are used to modify existing variables within functions
This is useful as it "moves" values around while minimizing copying of those values.
Reference variables modify existing variables within functions/programs
I don't know if you guys can still read this or not since it has been flagged a duplicate. I've been playing with a few of the mini-programs you guys have given me, re-read portions of my book, done further research, etc., and I think I understand on a rudimentary level. These reference variables allow you to alter and/or use other variables within your code without pulling them directly into your code. I can't remember which user was using the foo(hubble, bubble) example, but it was his/her code that finally made it click. Instead of just using the value, you are actually using and/or reassigning the variable.
A reference variable is nothing but an alias name of the variable. You would use it when you wanted to just pass the value around instead of copying the same variable into memory at a different location. So, using reference, copy can be avoidable which saves the memory.
According to Bjarne Stroustrup's FAQ:
C++ inherited pointers from C, so I couldn't remove them without
causing serious compatibility problems. References are useful for
several things, but the direct reason I introduced them in C++ was to
support operator overloading. For example:
void f1(const complex* x, const complex* y) // without references
{
complex z = *x+*y; // ugly
// ...
}
void f2(const complex& x, const complex& y) // with references
{
complex z = x+y; // better
// ...
}
More generally, if you want to have both the functionality of pointers
and the functionality of references, you need either two different
types (as in C++) or two different sets of operations on a single
type. For example, with a single type you need both an operation to
assign to the object referred to and an operation to assign to the
reference/pointer. This can be done using separate operators (as in
Simula). For example:
Ref<My_type> r :- new My_type;
r := 7; // assign to object
r :- new My_type; // assign to reference
Alternatively, you could rely on type checking (overloading). For
example:
Ref<My_type> r = new My_type;
r = 7; // assign to object
r = new My_type; // assign to reference
Also, read this Stack Overflow question about the differences between a pointer variable and a reference variable.
I will give three reasons, but there are many more.
Avoiding unnecessary copies.
Suppose you write a function like so:
double price(std::vector<Room> rooms)
{
...
}
Now, every time you call it, the vector of Room will be copied. If you only compute the prices of a few rooms that's fine, but if you want to compute the cost of repainting the entirety of the offices of the Empire State Building, you will start to copy huge objects, and this takes time.
It is better in this case to use a constant reference that provides read-only access to the data:
double price(const std::vector<Room>& rooms) { ... }
Using polymorphism
Suppose you now have different types of rooms, perhaps a CubicRoom and a CylindricalRoom, that both inherit from the same base class, Room.
It is not possible to write:
double price(Room room) { ... }
and then call
price(CylindricalRoom());
//or
price(CubicRoom());
but you can if you define price as follows:
double price(Room& room);
Everything then works the same as if you passed by value.
Avoiding returns
Suppose that each time you compute a price, you want to add a formatted quote to a report. In C++ you can only return a single object from a function, so you can not write:
return price, fmtQuote
However, you can do:
double price(Room room, std::vector<std::string>& quotes)
{
...
quotes.push_back(fmtQuote);
return price
}
Obviously, you could return a pair of objects std::pair<double, std::string>, but this means that the caller has to unpack the result. If you intend to call often the above function, this will quickly become ugly. In this case, this ties in to the first point: the log of all quotes will grow, and you do not want to copy it for each call.
This is a typical access pattern for shared resources: you want a few functions/objects to get a handle on a resource, not a copy of that resource.
You're mixing up two completely separate things here. Three examples to show how the two things work, individually and then together...
A function can take a parameter passed by value, and return a value.
double foo (double y)
{
y = y + 200.0;
return y;
}
void main(void)
{
double hubble = 50.0;
double bubble = 100.0;
hubble = foo(bubble);
std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
}
Note that because this is passed by value, even though foo() changes y, bubble does not change. hubble is set to the value returned by foo().
Then you get
hubble=300, bubble=100
A function can take a parameter passed by reference, and modify that parameter.
void foo (double& y)
{
y = y + 200.0;
}
void main(void)
{
double hubble = 50.0;
double bubble = 100.0;
foo(bubble);
std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
}
Then you get
hubble=50, bubble=300
Of course hubble hasn't changed. But because bubble was passed by reference, the change to y inside foo() changes bubble, because that change is happening on the actual variable passed and not on a copied value.
Note that you do not have a "return" statement here. The function does not return anything - it simply modifies the variable which is passed to it.
And of course you can use both together.
double foo (double& y)
{
y = y + 200.0;
return y + 400.0;
}
void main(void)
{
double hubble = 50.0;
double bubble = 100.0;
hubble = foo(bubble);
std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
}
Then you get
hubble=700, bubble=300
As before, changing y inside foo() changes bubble. But now the function is returning a value as well, which sets hubble.
Why would you choose to return a value, or to modify the value passed in, or to do both? That entirely depends on how you write your code.
I agree with you that you don't have to use a pass-by-reference here. Myself, I'd probably just return a value. But this is a learning exercise, and you've been told to do it that way, so you've got to. Suppose your pass-by-reference is the discount? So a function "void discount(double& value)" takes the value passed and multiplies it by 0.85. It's a bit artificial, but it would demonstrate the principle.
Reference variables are a safer alternative to pointers. Usually, when dealing with pointers you don't really care about the pointer (ptr) so much as what it points to (*ptr); and yet, all the time programmers screw up and manipulate ptr instead of *ptr and so on. Consider this code:
void zeroize_by_pointer(int* p)
{
p = 0; // this compiles, but doesn't do what you want
}
Compare to the reference version,
void zeroize_by_reference(int& p)
{
p = 0; // works fine
}
There are many other reasons why references are a good idea, but for someone starting out in C++ I'd suggest focusing on this one: it makes it slightly harder to shoot yourself in the foot. Whenever you deal with pointers you're going to be dealing on some level with the machine's memory model, and that's a good thing to avoid when possible.
There is another, more general advantage of references that pointers do not provide. References by their very nature allow you to express through the function signature that the object referred to must exist at the time the function is called No nulls allowed.
The caller cannot reasonably expect a function that takes a reference to check the validity of that reference..
Pointers, on the other hand, may validly be null. If I write a function that accepts a pointer...
void increment(int* val)
{
(*val)++;
}
...and the caller supplies null, my program is probably going to crash. I can write all the documentation I want stating that the pointer must not be null but the fact is it's pretty easy for someone to pass it in accidentally. So if I want to be safe, I must check for it.
But write this function with a reference and the intent is clear. No nulls allowed.
References were introduced primarily to support operator overloading. Using pointers for "passing via reference" would give you unacceptable syntax according to Bjarne Stroustrup. They also allow aliasing.
In addition, they allow object-oriented programming with a nicer syntax than using pointer explicitly. If you are using classes you must pass references to avoid object slicing.
In summary, you should always prefer using references over bare pointers.
You could almost always use reference variables (instead of ever passing by value): for example ...
// this function creates an estimate
// input parameter is the Rooms to be painted
// passed as a const reference because this function doesn't modify the rooms
// return value is the estimated monetary cost
Money createEstimate(const Rooms& rooms)
{
...
}
// this function adds paint to the rooms
// input parameter is the Rooms to be painted
// passed as a non-const reference because this function modifies the rooms
void paintRooms(Rooms& rooms)
{
...
}
When you pass-by-value instead of pass-by-reference then you implicitly create and pass a copy of the thing ...
// creates and passes a copy of the Rooms to the createEstimate function
Money createEstimate(Rooms rooms)
{
...
}
... which (creating a copy) is (often, slightly) slower than passing by reference (furthermore, creating a copy may have side-effects).
As a possible slight performance optimization, and by convention (because people don't care), it's common to pass-by-value instead of pass-be-reference when the type is small and simple (a.k.a. a "primitive" type), for example:
// passes a copy of the x and y values
// returns the sum
int add(int x, int y)
{
...
}
... instead of ...
// passes a reference to x and y
// returns the sum
int add(const int& x, const int& y)
{
...
}
See also Passing a modifiable parameter to c++ function as well as Why have pointer parameters?
There are also different kinds of references. We have lvalue and rvalue references, designated by & and &&, respectively. Generally, a reference tells us something about the lifetime of the object it references, a pointer does not. Compare
void foo(int* i);
void foo(int& i);
void foo(int&& i);
In the first case, i might point to an object we can assign to, but more importantly, it may also be a nullptr or point to one-past-the-end of an array. Thus, dereferencing it may lead to undefined behaviour. Checking for a nullptr is easy enough, the other check is not.
The the second case and third case, i must always reference an valid int we can assign too.
The difference between rvalue and lvalue references is that rvalue/&& references convey the meaning that the referenced value is not needed by anyone else and as such, allows for optimizations. Read up on std::move and move constructors to see what I mean.
To summarize: references tell us something about the object's lifetime. Sure, this could be stated in the documentation, but with pointers, violations of that contract might be hard to catch. References enforce the contract (to a high degree) at compile time and as such provide documentation to the code implicitly. This allows for some quick, uncomplicated optimizations by using e.g. move constructors or perfect forwarding in some cases.
Reference arguments are more used when you pass an object as argument. That way you don't copy the whole variable; usually they come with a const modifier like:
void printDescription(const Person& person) { ... }
That way you don't copy the object.
Sometime the return type is also set as a reference. That way you are returning the same object (and not a copy of it). Have a look at the << operator of ostream. ostream& operator<< (streambuf* sb );.
With variables you can think about the case where you can swap values.
void swap(int & a, int & b) {
int aux = a;
int a = b;
int b = aux;
}
This case in Java, for example, has to be done in a more complex way.
Reference variables are pointers without a * and practically without pointer arithmetics.
They are not needed from the C++, they are only syntactic sugar around them.
The initial idea of the creators was probably to make C++ code better comprehensible, although they reached its exact opposite.
My opinion is that a C++ program is better if it entirely misses reference variables and it uses only pointers.
Your function in the form
double foo (double studentID* y)
{
*y = 21654;
return *y;
}
...would do exactly the same, but it would be actually better comprehensible.
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.
Consider the sample application below. It demonstrates what I would call a flawed class design.
#include <iostream>
using namespace std;
struct B
{
B() : m_value(1) {}
long m_value;
};
struct A
{
const B& GetB() const { return m_B; }
void Foo(const B &b)
{
// assert(this != &b);
m_B.m_value += b.m_value;
m_B.m_value += b.m_value;
}
protected:
B m_B;
};
int main(int argc, char* argv[])
{
A a;
cout << "Original value: " << a.GetB().m_value << endl;
cout << "Expected value: 3" << endl;
a.Foo(a.GetB());
cout << "Actual value: " << a.GetB().m_value << endl;
return 0;
}
Output:
Original value: 1
Expected value: 3
Actual value: 4
Obviously, the programmer is fooled by the constness of b. By mistake b points to this, which yields the undesired behavior.
My question: What const-rules should you follow when designing getters/setters?
My suggestion: Never return a reference to a member variable if it can be set by reference through a member function. Hence, either return by value or pass parameters by value. (Modern compilers will optimize away the extra copy anyway.)
Obviously, the programmer is fooled by the constness of b
As someone once said, You keep using that word. I do not think it means what you think it means.
Const means that you cannot change the value. It does not mean that the value cannot change.
If the programmer is fooled by the fact that some other code else can change something that they cannot, they need a better grounding in aliasing.
If the programmer is fooled by the fact that the token 'const' sounds a bit like 'constant' but means 'read only', they need a better grounding in the semantics of the programming language they are using.
So if you have a getter which returns a const reference, then it is an alias for an object you don't have the permission to change. That says nothing about whether its value is immutable.
Ultimately, this comes down to a lack of encapsulation, and not applying the Law of Demeter. In general, don't mutate the state of other objects. Send them a message to ask them to perform an operation, which may (depending on their own implementation details) mutate their state.
If you make B.m_value private, then you can't write the Foo you have. You either make Foo into:
void Foo(const B &b)
{
m_B.increment_by(b);
m_B.increment_by(b);
}
void B::increment_by (const B& b)
{
// assert ( this != &b ) if you like
m_value += b.m_value;
}
or, if you want to ensure that the value is constant, use a temporary
void Foo(B b)
{
m_B.increment_by(b);
m_B.increment_by(b);
}
Now, incrementing a value by itself may or may not be reasonable, and is easily tested for within B::increment_by. You could also test whether &m_b==&b in A::Foo, though once you have a couple of levels of objects and objects with references to other objects rather than values (so &a1.b.c == &a2.b.c does not imply that &a1.b==&a2.b or &a1==&a2), then you really have to just be aware that any operation is potentially aliased.
Aliasing means that incrementing by an expression twice is not the same as incrementing by the value of the expression the first time you evaluated it; there's no real way around it, and in most systems the cost of copying the data isn't worth the risk of avoiding the alias.
Passing in arguments which have the least structure also works well. If Foo() took a long rather than an object which it has to get a long from, then it would not suffer aliasing, and you wouldn't need to write a different Foo() to increment m_b by the value of a C.
I propose a slightly different solution to this that has several advantages (especially in an every increasing, multi-threaded world). Its a simple idea to follow, and that is to "commit" your changes last.
To explain via your example you would simply change the 'A' class to:
struct A
{
const B& GetB() const { return m_B; }
void Foo(const B &b)
{
// copy out what we are going to change;
int itm_value = m_b.m_value;
// perform operations on the copy, not our internal value
itm_value += b.m_value;
itm_value += b.m_value;
// copy over final results
m_B.m_value = itm_value ;
}
protected:
B m_B;
};
The idea here is to place all assignment to memory viewable above the current function at the end, where they pretty much can't fail. This way, if an error is thrown (say there was a divide in the middle of those 2 operations, and if it just happens to be 0) in the middle of the operation, then we aren't left with half baked data in the middle.
Furthermore, in a multi-threading situation, you can do all of the operation, and then just check at the end if anything has changed before your "commit" (an optimistic approach, which will usually pass and usually yield much better results than locking the structure for the entire operation), if it has changed, you simply discard the values and try again (or return a value saying it has failed if there is something it can do instead).
On top of this, the compiler can usually optimise this better, because it is no longer required to write the variables being modified to memory (we are only forcing one read of the value to be changed and one write). This way, the compiler has the option of just keeping the relevant data in a register, saves L1 cache access if not cache misses. Otherwise the compiler will probably make it write to the memory as it doesn't know what aliasing might be taking place (so it can't ensure those values stay the same, if they are all local, it knows it can't be aliasing because the current function is the only one that knows about it).
There's a lot of different things that can happen with the original code posted. I wouldn't be surprised if some compilers (with optimizations enabled) will actually produce code that produces the "expected" result, whereas others won't. All of this is simply because the point at which variables, that aren't 'volatile', are actually written/read from memory isn't well defined within the c++ standards.
The real problem here is atomicity. The precondition of the Foo function is that it's argument doesn't change while in use.
If e.g. Foo had been specified with a value-argument i.s.o. reference argument, no problem would have shown.
Frankly, A::Foo() rubs me the wrong way more than your original problem. Anyhow I look at it, it must be B::Foo(). And inside B::Foo() check for this wouldn't be that outlandish.
Otherwise I do not see how one can specify a generic rule to cover that case. And keep teammates sane.
From past experience, I would treat that as a plain bug and would differentiate two cases: (1) B is small and (2) B is large. If B is small, then simply make A::getB() to return a copy. If B is large, then you have no choice but to handle the case that objects of B might be both rvalue and lvalue in the same expression.
If you have such problems constantly, I'd say simpler rule would be to always return a copy of an object instead of a reference. Because quite often, if object is large, then you have to handle it differently from the rest anyway.
My stupid answer, I leave it here just in case someone else comes up with the same bad idea:
The problem is I think that the object referred to is not const (B const & vs const B &), only the reference is const in your code.
I know there are few question about const correctness where it is stated that the declaration of a function and its definition do not need to agree for value parameters. This is because the constness of a value parameter only matters inside the function. This is fine:
// header
int func(int i);
// cpp
int func(const int i) {
return i;
}
Is doing this really a best practice? Because I've never seen anyone do it. I've seen this quotation (not sure of the source) in other places this has been discussed:
"In fact, to the compiler, the function signature is the same whether you include this const in front of a value parameter or not."
"Avoid const pass-by-value parameters in function declarations. Still make the parameter const in the same function's definition if it won't be modified."
The second paragraph says to not put the const in the declaration. I assume this is because the constness of a value parameter is meaningless as part of a interface definition. It is an implementation detail.
Based on this recommendation, is it also recommended for the pointer values of pointer parameters? (It is meaningless on a reference parameter since you can't reassign a reference.)
// header
int func1(int* i);
int func2(int* i);
// cpp
int func1(int* i) {
int x = 0;
*i = 3; // compiles without error
i = &x; // compiles without error
return *i;
}
int func2(int* const i) {
int x = 0;
*i = 3; // compiles without error
i = &x; // compile error
return *i;
}
Summary: Making value parameters is useful to catch some logic errors. Is it a best practice? Do you go to the extreme of leaving the const out of the header file? Is it just as useful to const pointer values? Why or why not?
Some references:
C++ const keyword - use liberally?
Use of 'const' for function parameters
An example of when const value parameters are useful:
bool are_ints_equal(const int i, const int j) {
if (i = j) { // without the consts this would compile without error
return true;
} else {
return false;
}
// return i = j; // I know it can be shortened
}
I've read many times that making value parameters in a function const is a bad thing to do because it's unnecessary.
However, I find it occasionally helpful to me as a check that my implementation doesn't do something I don't intend (as in the example at the end of your question).
So, while it may not add value to the caller, it does sometimes add a small bit of value to me as an implementer, and it doesn't take anything away from the caller. So I see no harm using it.
For example, I may be implementing a C function that takes a couple pointers to a buffer - a pointer to the start, and a pointer to the end. I'm going to put data in the buffer, but want to ensure that I don't overrun the end. So inside the function there's code that will increment a pointer as I'm adding data to it. Making the pointer to the end of the buffer a const parameter will ensure that I don't code up a bug that accidentally increments the end boundary pointer instead of the pointer I really should be incrementing.
So a fillArray function with a signature like this:
size_t fillArray( data_t* pStart, data_t* const pEnd);
will prevent me from accidentally incrementing pEnd when I really mean to increment pStart. It's not a huge thing, but I'm pretty sure everyone who has programmed for any period of time in C has run across such a bug.
My take on it:
It's not a bad idea, but the issue is minor and your energy might be better spent on other things.
In your question you provided a good example of when it might catch an error, but occasionally you also end up doing something like this:
void foo(const int count /* … */)
{
int temp = count; // can't modify count, so we need a copy of it
++temp;
/* … */
}
The pros and cons are minor either way.
Unfortunately, some compilers (I'm looking at you, Sun CC!) incorrectly differentiate between arguments declared const and ones not declared so, and you can get errors about undefined functions.
I think this is dependent on your personal style.
It doesn't add or subtract to what clients can pass to your function. In essence it's like a compile-time assertion. If it helps you to know that value won't change, go ahead and do it, but I don't see a big reason for others to do it.
One reason I might not do it is that the const-ness of the value parameter is an implementation detail that your clients don't need to know about. If you later (purposely) change your function so that it actually does change that value, you will need to change the signature of your function, which will force your clients to re-compile.
This is similar to why some people recommend having no public virtual methods (the functions virtual-ness is an implementation detail that should be hidden from clients), but I'm not in that particular camp.
If there is const keyword present; it means value of 'i' (which is const type) can not be modified.
If value of 'i' is changed inside foo function compiler will throw error: "
Can not modify const object
But changing '*i' (i.e. *i = 3;)means you are not changing value of 'i' but value of address pointed by 'i'
Actually,the const function is appropriate for large objects that should not be altered by function.
I like const correctness for situations like this:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}
This lets me use b without fear of modifying it, but I don't have to pay the cost of a copy constructor.
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.