Skip to main content
added 1057 characters in body
Source Link
Christophe
  • 82.3k
  • 11
  • 136
  • 202

Let's start with the non const approachThe non-const approach:

Here the compiler has to assume that k could be changed by f()f(), because this function is unknown. So the generated code has to make the calculation of ii, even if we'd know that f() doesn't change the value pointed at.

Now the same code with const approach would look like:The const approach:

First of all, the const_castconst_cast shows that we are taking a risk. So we have to be really sure that f()f() will not change the value pointed at (if not it would be undefined behavior).

The clean const approach:

Of course const_castconst_cast is something risky, and should be avoided if possible. And that's where the second level benefit of using const appears: you become sensitive to this kind of subtleties, and you'll start increasing const discipline, rewriting the ff() properly by making constness explicit as well:

This code is event better, because not only are you sure that k is constant, but everybody now knows that f() doesn't change the pointed value, and the compiler can do better constant propagation.

Let's start with the non const approach:

Here the compiler has to assume that k could be changed by f(), because this function is unknown. So the generated code has to make the calculation of i, even if we'd know that f() doesn't change the value pointed at.

Now the same code with const approach would look like:

First of all, the const_cast shows that we are taking a risk. So we have to be really sure that f() will not change the value pointed at (if not it would be undefined behavior).

Of course const_cast is something risky, and should be avoided if possible. And that's the second level benefit of using const: you become sensitive to this kind of subtleties, and you'll start increasing discipline, rewriting the f properly by making constness explicit as well:

The non-const approach:

Here the compiler has to assume that k could be changed by f(), because this function is unknown. So the generated code has to make the calculation of i, even if we'd know that f() doesn't change the value pointed at.

The const approach:

First of all, the const_cast shows that we are taking a risk. So we have to be really sure that f() will not change the value pointed at (if not it would be undefined behavior).

The clean const approach:

Of course const_cast is something risky, and should be avoided if possible. And that's where the second level benefit of using const appears: you become sensitive to this kind of subtleties, and you'll start increasing const discipline, rewriting the f() properly by making constness explicit as well:

This code is event better, because not only are you sure that k is constant, but everybody now knows that f() doesn't change the pointed value, and the compiler can do better constant propagation.

added 1057 characters in body
Source Link
Christophe
  • 82.3k
  • 11
  • 136
  • 202
  • it clarifies your intention: everybody will understand that this variable is not supposed to vary.
  • it avoids stupid mistakes, where a typo would have caused your value to change
  • it forces discipline: if you use pointers or references to that variable, the compiler will complain if it is a non const pointer or reference, that could lead to subtle errors.
  • furthermore, this will encourage discipline in assessing constness of arguments passed by reference or via pointers, which will ultimately avoid more subtle errors and code which is easier to verify.
  • it allows the compiler to make assumptions and optimizations, that could otherwise not be made in certain circumstances.
  • it clarifies your intention: everybody will understand that this variable is not supposed to vary.
  • it avoids stupid mistakes, where a typo would have caused your value to change
  • it forces discipline: if you use pointers or references to that variable, the compiler will complain if it is a non const pointer or reference, that could lead to subtle errors.
  • it allows the compiler to make assumptions and optimizations, that could otherwise not be made in certain circumstances.
  • it clarifies your intention: everybody will understand that this variable is not supposed to vary.
  • it avoids stupid mistakes, where a typo would have caused your value to change
  • it forces discipline: if you use pointers or references to that variable, the compiler will complain if it is a non const pointer or reference, that could lead to subtle errors.
  • furthermore, this will encourage discipline in assessing constness of arguments passed by reference or via pointers, which will ultimately avoid more subtle errors and code which is easier to verify.
  • it allows the compiler to make assumptions and optimizations, that could otherwise not be made in certain circumstances.
added 1057 characters in body
Source Link
Christophe
  • 82.3k
  • 11
  • 136
  • 202

Let me develop the last point with a small and silly example.


Let's start with the non const approach:

Here the compiler has to assume that k could be changed by f(), because this function is unknown. So the generated code has to make the calculation of i, even if we'd know that f() doesn't change the value pointed at.


Now the same code with const approach would look like:

int main() { const int k = 10; f(const_cast<int*>(&k)); // ATTENTION: we have to be sure about the cast!! int i = k*k+2*k+1; std::cout<<i; } 

Of courseFirst of all, to write thisthe const_cast shows that we are taking a risk. So we have to knowbe really sure that f() will not change the value pointed at (if not it would be undefined behavior). But

But the compiler could then generate a much faster code:

 mov DWORD PTR [rsp+12], 10 call f(int*) mov esi, 121 // the compiler could make the calculation upfront! 

Of course const_cast is something risky, and should be avoided if possible. And that's the second level benefit of using const: you become sensitive to this kind of subtleties, and you'll start increasing discipline, rewriting the f properly by making constness explicit as well:

extern void f(const int *p); // if parameter remains const, tell it ! int main() { const int k = 10; f(&k);  // the compiler knows that k will not change  int i = k*k+2*k+1; // the compiler knows it's 121 std::cout<<i; } 

Of course, passing parameters by reference would produce similar results.

Let me develop the last point with a small and silly example:

Now the same code with const would look like:

int main() { const int k = 10; f(const_cast<int*>(&k)); // we have to be sure about the cast!! int i = k*k+2*k+1; std::cout<<i; } 

Of course, to write this we have to know that f() will not change the value pointed at (if not it would be undefined behavior). But the compiler could then generate:

 mov DWORD PTR [rsp+12], 10 call f(int*) mov esi, 121 // the compiler could make the calculation upfront! 

Let me develop the last point with a small and silly example.


Let's start with the non const approach:

Here the compiler has to assume that k could be changed by f(), because this function is unknown. So the generated code has to make the calculation of i, even if we'd know that f() doesn't change the value pointed at.


Now the same code with const approach would look like:

int main() { const int k = 10; f(const_cast<int*>(&k)); // ATTENTION: we have to be sure about the cast!! int i = k*k+2*k+1; std::cout<<i; } 

First of all, the const_cast shows that we are taking a risk. So we have to be really sure that f() will not change the value pointed at (if not it would be undefined behavior).

But the compiler could then generate a much faster code:

 mov DWORD PTR [rsp+12], 10 call f(int*) mov esi, 121 // the compiler could make the calculation upfront! 

Of course const_cast is something risky, and should be avoided if possible. And that's the second level benefit of using const: you become sensitive to this kind of subtleties, and you'll start increasing discipline, rewriting the f properly by making constness explicit as well:

extern void f(const int *p); // if parameter remains const, tell it ! int main() { const int k = 10; f(&k);  // the compiler knows that k will not change  int i = k*k+2*k+1; // the compiler knows it's 121 std::cout<<i; } 

Of course, passing parameters by reference would produce similar results.

Source Link
Christophe
  • 82.3k
  • 11
  • 136
  • 202
Loading