Isn't "const" redundant when passing by value? [duplicate] - c++

This question already has answers here:
Use of 'const' for function parameters
(31 answers)
Closed 7 years ago.
I was reading my C++ book (Deitel) when I came across a function to calculate the volume of a cube. The code is the following:
double cube (const double side){
return side * side * side;
}
The explanation for using the "const" qualifier was this one: "The const qualified should be used to enforce the principle of least privilege, telling the compiler that the function does not modify variable side".
My question: isn't the use of "const" redundant/unnecessary here since the variable is being passed by value, so the function can't modify it anyway?

The const qualifier prevents code inside the function from modifying the parameter itself. When a function is larger than trivial size, such an assurance helps you to quickly read and understand a function. If you know that the value of side won't change, then you don't have to worry about keeping track of its value over time as you read. Under some circumstances, this might even help the compiler generate better code.
A non-trivial number of people do this as a matter of course, considering it generally good style.

You can do something like this:
int f(int x)
{
x = 3; //with "const int x" it would be forbidden
// now x doesn't have initial value
// which can be misleading in big functions
}

Related

"Type&" vs "Type*" in C++ function definitions [duplicate]

This question already has answers here:
What are the differences between a pointer variable and a reference variable?
(44 answers)
Closed 4 years ago.
I understand the pointer concept (int*), but I cannot understand int& because they give the same result. What does int &data exactly mean?
void add1(int *data){
(*data)++;
}
void add2(int &data){
data++;
}
int main()
{
int i=0;
add1(&i);
printf ("value i = %d\n",i) // show 1
add2(i);
printf ("value i = %d\n",i); // show 2
return 0;
}
The function signature:
void add2(int &data)
is the pass-by-reference facility in C++. It's a way to allow the function to change the value passed in and have that change reflected back to the caller. In C, upon which C++ was originally based, all paramaters are pass-by-value, meaning the functions get a local copy which, if changed, does not affect the original value passed in.
As an aside, pass by reference is probably the one facility I'd most like to see added to C (not full-blown C++ references, just in the function calls) since I'm pretty certain 42% of all C questions here on SO have to do with pointers :-)
The way to do pass-by-reference in C and C++ can be seen in the lines below. The first is the right way to do it in C++, and the second is the "pointer gymnastics" poor C developers have to go through to get the same effect:
void FortyTwo(int &x) { x = 42; } // Call with FortyTwo(variable);
void FortyTwo(int *pX) { *pX = 42; } // Call with FortyTwo(&variable);
In the latter, the pointer is passed by value but you can use that pointer to get at (and change) the data it points to. In C++, you should, as much as possible, avoid passing the pointers to values you want to change since that's one of the reasons references were added to C++ in the first place. It also makes your code easier to understand if you don't have to pepper it with pointer dereferences.

Benefit of constexpr on non-changing expressions [duplicate]

This question already has answers here:
When should you use constexpr capability in C++11?
(15 answers)
Closed 6 years ago.
So I understand that the use of constexpr in C++ is for defined expressions that are be evaluated at compile time, and more obviously to declare a variable or function as a constant expression. My confusion comes from understanding any benefits of using it for simple functions that will not change.
Suppose you have a function to simply square a value...
int square(int x) {
return x * x;
}
Typically that will never change, or be overridden, however, I've seen people say that it would be better practice to instead define it as...
constexpr int square(int x) {
return x * x;
}
To me, this seems like such a trivial change. Can anyone enlighten me on serious advantages of declaring such simple expressions as constexpr?
The advantage of that change is that whenever x is known at compile time, result of square could be used to initialize constexpr variables or as a template argument.

Why use const proactively? C++ [duplicate]

This question already has answers here:
Why aren't C++ types const by default?
(3 answers)
Closed 9 years ago.
I read a lot article from website, it said that const help to understand the source better because you have an insurance that the value is fixed. Is this the only reason using const?
By using const you are using the compiler to spot when you are trying to write to something that you shouldn't. I think that having the compiler tell me that I am doing something wrong is always good. Also many compilers will optimise more efficiently when given the information that something in not ever going to change.
It's a good reason, but another is that when you use references wheither they are const or not makes a big difference. For instance
void f(string& ref);
void g(const string& ref);
string h();
f(h()); // illegal code
g(h()); // legal code
The difference is because of the rule you cannot bind a temporary to a non-const reference. The return value of h is a temporary, and so only the call to g is legal. If you have f you would need to use an additional variable
string tmp = h();
f(tmp);

const_casting question [duplicate]

This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
I have the following code:
int main(){
const int a = 1;
const int* b(&a);
int* c = const_cast<int*>(b);
*c = 29;
cout<<*c<<a<<*b;
return EXIT_SUCCESS;
}
Why doesnt the value of 'a' change to 29? Does this mean that the constness of a is not removed when const_casting b?
Constant variables also allows the compiler certain optimizations, one of these is that the compiler can keep the value in the registers and not reload it. This improves performance but will not work with variables that changes since these need to be reread. Some compilers even optimize constants by not allocating a variable, but simply replacing the value inline. If you change the variable a to int instead of const int it will work, as it can be read in the documentation about the const_cast operator from IBM:
If you cast away the constness of an
object that has been explicitly
declared as const, and attempt to
modify it, the results are undefined.
You can find more information about the problem you are having and why it doesn't work here:
The const_cast operator (IBM)
C++ const_cast usage instead of
C-style
casts
const_cast
confusion
On a side note it can be noted that if you find yourself in need of using the const_cast there is a good chance that you should reconsider your design instead.

C++ beginner question: dereference vs multiply [duplicate]

This question already has an answer here:
What's the meaning of * and & when applied to variable names?
(1 answer)
Closed 7 years ago.
Just getting into C++. I'm getting constantly thrown off track when I see the symbol for multiply (*) being used to denote the dereferencing of a variable
for example:
unsigned char * pixels = vidgrabber.getPixels();
Does this throw other people off? What's the tip for getting my head around this?
Thank you.
p.s. I have another reasonably simple question, that didn't get answered :( here: beginner question: add/subtract to value rather than just be that value pretty please! and thanks for your time!
C, and by inheritance C++, are swamped with operators and are inherently context-sensitive. You will have to get used to it:
If * appears before the name of a variable that is being declared (or defined), it's a type modifier and makes that variable a pointer.
If it is a unary prefix operator for a variable that is part of an expression, it's dereferencing (or whatever it's been overloaded to).
If it is a binary infix operator for two variables that are part of an expression, it's multiplication (or whatever it's been overloaded to).
(From this you can see that the * in your unsigned char * pixel isn't a dereferencing unary prefix, but a type modifier.)
Note that & pretty much resembles *, only it's meaning is different: it makes a variable a reference, is the address-of operator, or the binary AND.
One recommendation when writing your own code is to "cuddle" the * when using as a pointer/deref:
unsigned char *pixels = ...
if (*pixels == ...)
and to space the * when using as a multiply:
int y = x * 7;
There are other clues you can use (such as the fact that pointer deref is a unary operator while multiple is a binary operator).
The answer is: practice. Every new programming language will look funny to some extent, some funnier than others. Learn to use it and it will become natural.
You can distinguish the dereference operator from the multiplication operaotr by the fact that, usually, a multiplicator operator doesn't have a type name on his left.
Contrived Example
You wrote about dereferencing in C.
Can you tell the result from just looking at it? ==>
int v[] = {5,6}, w[] = {7,8};
int m[][2] = { {1,2}, {3,4} };
int result = * v * * * m * * w;
Regards
rbo
The same way English speakers get around the fact that the same word can have different meanings depending on the context. Once you are somewhat immersed in the context, it will usually be obvious what the operator is doing.
An important thing to note about C compared with other languages is that in when multiple declarations are combined in one statement, the asterisk applies to individual items, not the set as a whole. For example:
int* foo,bar;
creates an int-pointer called foo, and an int called bar. I always peg the asterisk to the variable, and I avoid mixing pointers and non-pointers in one statement thus:
int *foo;
int *ptr1,*ptr2,*ptr3;
int bar,boz,baz;
It's also important to note that storage-class qualifiers like 'const' and 'volatile' may not always bind as one would expect. The statement
volatile int *foo;
does not mean that 'foo' is a volatile, but rather that what 'foo' points to is a volatile. If foo itself is the 'volatile' thing, one must write "int * volatile foo;"