David Holm
David Holm

Reputation: 17980

Constants and compiler optimization in C++

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?

Upvotes: 52

Views: 23073

Answers (12)

Mike Dunlavey
Mike Dunlavey

Reputation: 40699

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 third-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).

Upvotes: 2

Michael Burr
Michael Burr

Reputation: 340446

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.

Let’s disregard objects that may have mutable members. The compiler is free to assume that the object will not be and 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.

Upvotes: 36

Konrad Rudolph
Konrad Rudolph

Reputation: 546073

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.

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?

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.

Upvotes: 0

Luc Touraille
Luc Touraille

Reputation: 82161

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 doesn't have any 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.

Upvotes: 55

Skizz
Skizz

Reputation: 71120

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

Upvotes: 0

MSN
MSN

Reputation: 54634

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

Upvotes: -1

David Thornley
David Thornley

Reputation: 57066

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.

Upvotes: 1

Rob Walker
Rob Walker

Reputation: 47502

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.

Upvotes: 1

Mike F
Mike F

Reputation:

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.

Upvotes: 5

Andrew Stein
Andrew Stein

Reputation: 13180

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.

Upvotes: 3

James Curran
James Curran

Reputation: 103575

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.

Upvotes: 4

Paul Nathan
Paul Nathan

Reputation: 40319

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

Upvotes: 6

Related Questions