Constants and compiler optimization in C++

C++OptimizationCompiler Construction

C++ Problem Overview


I've read all the advice on const-correctness in C++ and that it is important (in part) because it helps the compiler to optimize your code. What I've never seen is a good explanation on how the compiler uses this information to optimize the code, not even the good books go on explaining what happens behind the curtains.

For example, how does the compiler optimize a method that is declared const vs one that isn't but should be. What happens when you introduce mutable variables? Do they affect these optimizations of const methods?

C++ Solutions


Solution 1 - C++

I think that the const keyword was primarily introduced for compilation checking of the program semantic, not for optimization.

Herb Sutter, in the GotW #81 article, explains very well why the compiler can't optimize anything when passing parameters by const reference, or when declaring const return value. The reason is that the compiler has no way to be sure that the object referenced won't be changed, even if declared const : one could use a const_cast, or some other code can have a non-const reference on the same object.

However, quoting Herb Sutter's article :

> There is [only] one case where saying > "const" can really mean something, and > that is when objects are made const at > the point they are defined. In that > case, the compiler can often > successfully put such "really const" > objects into read-only memory[...].

There is a lot more in this article, so I encourage you reading it: you'll have a better understanding of constant optimization after that.

Solution 2 - C++

Let's disregard methods and look only at const objects; the compiler has much more opportunity for optimization here. If an object is declared const, then (ISO/IEC 14882:2003 7.1.5.1(4)):

> Except that any class member declared > mutable (7.1.1) can be modified, any > attempt to modify a const object > during its lifetime (3.8) results in > undefined behavior.

Lets disregard objects that may have mutable members - the compiler is free to assume that the object will not be modified, therefore it can produce significant optimizations. These optimizations can include things like:

  • incorporating the object's value directly into the machines instruction opcodes
  • complete elimination of code that can never be reached because the const object is used in a conditional expression that is known at compile time
  • loop unrolling if the const object is controlling the number of iterations of a loop

Note that this stuff applies only if the actual object is const - it does not apply to objects that are accessed through const pointers or references because those access paths can lead to objects that are not const (it's even well-defined to change objects though const pointers/references as long as the actual object is non-const and you cast away the constness of the access path to the object).

In practice, I don't think there are compilers out there that perform any significant optimizations for all kinds of const objects. but for objects that are primitive types (ints, chars, etc.) I think that compilers can be quite aggressive in optimizing the use of those items.

Solution 3 - C++

handwaving begins

Essentially, the earlier the data is fixed, the more the compiler can move around the actual assignment of the data, ensuring that the pipeline doesn't stall out

end handwaving

Solution 4 - C++

Meh. Const-correctness is more of a style / error-checking thing than an optimisation. A full-on optimising compiler will follow variable usage and can detect when a variable is effectively const or not.

Added to that, the compiler cannot rely on you telling it the truth - you could be casting away the const inside a library function it doesn't know about.

So yes, const-correctness is a worthy thing to aim for, but it doesn't tell the compiler anything it won't figure out for itself, assuming a good optimising compiler.

Solution 5 - C++

It does not optimize the function that is declared const.

It can optimize functions that call the function that is declared const.

void someType::somefunc();

void MyFunc()
{
    someType A(4);   // 
    Fling(A.m_val);
    A.someFunc();
    Flong(A.m_val);
}

Here to call Fling, the valud A.m_val had to be loaded into a CPU register. If someFunc() is not const, the value would have to be reloaded before calling Flong(). If someFunc is const, then we can call Flong with the value that's still in the register.

Solution 6 - C++

The main reason for having methods as const is for const correctness, not for possible compilation optimization of the method itself.

If variables are const they can (in theory) be optimized away. But only is the scope can be seen by the compiler. After all the compiler must allow for them to be modified with a const_cast elsewhere.

Solution 7 - C++

Those are all true answers, but the answers and the question seem to presume one thing: that compiler optimization actually matters.

There is only one kind of code where compiler optimization matters, that is in code that is

  • a tight inner loop,
  • in code that you compile, as opposed to a 3rd-party library,
  • not containing function or method calls (even hidden ones),
  • where the program counter spends a noticeable fraction of its time

If the other 99% of the code is optimized to the Nth degree, it won't make a hoot of difference, because it only matters in code where the program counter actually spends time (which you can find by sampling).

Solution 8 - C++

I would be surprised if the optimizer actually puts much stock into a const declaration. There is a lot of code that will end up casting const-ness away, it would be a very reckless optimizer that relied on the programmer declaration to assume when the state may change.

Solution 9 - C++

const-correctness is also useful as documentation. If a function or parameter is listed as const, I don't need to worry about the value changing out from under my code (unless somebody else on the team is being very naughty). I'm not sure it would be actually worth it if it wasn't built into the library, though.

Solution 10 - C++

The most obvious point where const is a direct optimization is in passing arguments to a function. It's often important to ensure that the function doesn't modify the data so the only real choices for the function signature are these:

void f(Type dont_modify); // or
void f(Type const& dont_modify);

Of course, the real magic here is passing a reference rather than creating an (expensive) copy of the object. But if the reference weren't marked as const, this would weaken the semantics of this function and have negative effects (such as making error-tracking harder). Therefore, const enables an optimization here.

/EDIT: actually, a good compiler can analyze the control flow of the function, determine that it doesn't modify the argument and make the optimization (passing a reference rather than a copy) itself. const here is merely a help for the compiler. However, since C++ has some pretty complicated semantics and such control flow analysis can be very expensive for big functions, we probably shouldn't rely on compilers for this. Does anybody have any data to back me up / prove me wrong?

/EDIT2: and yes, as soon as custom copy constructors come into play, it gets even trickier because compilers unfortunately aren't allowed to omit calling them in this situation.

Solution 11 - C++

This code,

class Test
{
public:
  Test (int value) : m_value (value)
  {
  }

  void SetValue (int value) const
  {
    const_cast <Test&>(*this).MySetValue (value);
  }

  int Value () const
  {
    return m_value;
  }

private:
  void MySetValue (int value)
  {
    m_value = value;
  }

  int
    m_value;
};

void modify (const Test &test, int value) 
{
  test.SetValue (value);
}

void main ()
{
  const Test
    test (100);

  cout << test.Value () << endl;
  modify (test, 50);
  cout << test.Value () << endl;
}

outputs:

100
50

which means the const declared object has been altered in a const member function. The presence of const_cast (and the mutable keyword) in the C++ language means that the const keyword can't aide the compiler in generating optimised code. And as I pointed out in my previous posts, it can even produce unexpected results.

As a general rule:

>const != optimisation

In fact, this is a legal C++ modifier:

volatile const

Solution 12 - C++

const helps compilers optimize mainly because it makes you write optimizable code. Unless you throw in const_cast.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid HolmView Question on Stackoverflow
Solution 1 - C++Luc TourailleView Answer on Stackoverflow
Solution 2 - C++Michael BurrView Answer on Stackoverflow
Solution 3 - C++Paul NathanView Answer on Stackoverflow
Solution 4 - C++Mike FView Answer on Stackoverflow
Solution 5 - C++James CurranView Answer on Stackoverflow
Solution 6 - C++Andrew SteinView Answer on Stackoverflow
Solution 7 - C++Mike DunlaveyView Answer on Stackoverflow
Solution 8 - C++Rob WalkerView Answer on Stackoverflow
Solution 9 - C++David ThornleyView Answer on Stackoverflow
Solution 10 - C++Konrad RudolphView Answer on Stackoverflow
Solution 11 - C++SkizzView Answer on Stackoverflow
Solution 12 - C++MSNView Answer on Stackoverflow