Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What kind of optimization does const offer in C/C++?

I know that where possible you should use the const keyword when passing parameters around by reference or by pointer for readability reasons. Is there any optimizations that the compiler can do if I specify that an argument is constant?

There could be a few cases:

Function parameters:

Constant reference:

void foo(const SomeClass& obj)

Constant SomeClass object:

void foo(const SomeClass* pObj)

And constant pointer to SomeClass:

void foo(SomeClass* const pObj)

Variable declarations:

const int i = 1234

Function declarations:

const char* foo()

What kind of compiler optimizations each one offers (if any)?

like image 812
UnTraDe Avatar asked Dec 14 '14 05:12

UnTraDe


People also ask

Does const improve performance in C?

const correctness can't improve performance because const_cast and mutable are in the language, and allow code to conformingly break the rules. This gets even worse in C++11, where your const data may e.g. be a pointer to a std::atomic , meaning the compiler has to respect changes made by other threads.

What does const does in C?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.

Does C have const correctness?

In C, C++, and D, all data types, including those defined by the user, can be declared const , and const-correctness dictates that all variables or objects should be declared as such unless they need to be modified.

What is compiler optimization in C?

Compiler optimization is generally implemented using a sequence of optimizing transformations, algorithms which take a program and transform it to produce a semantically equivalent output program that uses fewer resources or executes faster.


3 Answers

Source

Case 1:

When you declare a const in your program,

int const x = 2;

Compiler can optimize away this const by not providing storage for this variable; instead it can be added to the symbol table. So a subsequent read just needs indirection into the symbol table rather than instructions to fetch value from memory.

Note: If you do something like:

const int x = 1;
const int* y = &x;

Then this would force compiler to allocate space for x. So, that degree of optimization is not possible for this case.

In terms of function parameters const means that parameter is not modified in the function. As far as I know, there's no substantial performance gain for using const; rather it's a means to ensure correctness.


Case 2:

"Does declaring the parameter and/or the return value as const help the compiler to generate more optimal code?"

const Y& f( const X& x )
{
    // ... do something with x and find a Y object ...
    return someY;
}

What could the compiler do better? Could it avoid a copy of the parameter or the return value?

No, as argument is already passed by reference.

Could it put a copy of x or someY into read-only memory?

No, as both x and someY live outside its scope and come from and/or are given to the outside world. Even if someY is dynamically allocated on the fly within f() itself, it and its ownership are given up to the caller.

What about possible optimizations of code that appears inside the body of f()? Because of the const, could the compiler somehow improve the code it generates for the body of f()?

Even when you call a const member function, the compiler can't assume that the bits of object x or object someY won't be changed. Further, there are additional problems (unless the compiler performs global optimization): The compiler also may not know for sure that no other code might have a non-const reference that aliases the same object as x and/or someY, and whether any such non-const references to the same object might get used incidentally during the execution of f(); and the compiler may not even know whether the real objects, to which x and someY are merely references, were actually declared const in the first place.


Case 3:

void f( const Z z )
{
    // ...
}

Will there be any optimization in this?

Yes because the compiler knows that z truly is a const object, it could perform some useful optimizations even without global analysis. For example, if the body of f() contains a call like g( &z ), the compiler can be sure that the non-mutable parts of z do not change during the call to g().

like image 157
ravi Avatar answered Oct 18 '22 03:10

ravi


Before giving any answer, I want to emphasize that the reason to use or not use const really ought to be for program correctness and for clarity for other developers more so than for compiler optimizations; that is, making a parameter const documents that the method will not modify that parameter, and making a member function const documents that that member will not modify the object of which it is a member (at least not in a way that logically changes the output from any other const member function). Doing this, for example, allows developers to avoid making unnecessary copies of objects (because they don't have to worry that the original will be destroyed or modified) or to avoid unnecessary thread synchronization (e.g. by knowing that all threads merely read and do not mutate the object in question).

In terms of optimizations a compiler could make, at least in theory, albeit in an optimization mode that allows it to make certain non-standard assumptions that could break standard C++ code, consider:

for (int i = 0; i < obj.length(); ++i) {
   f(obj);
}

Suppose the length function is marked as const but is actually an expensive operation (let's say it actually operates in O(n) time instead of O(1) time). If the function f takes its parameter by const reference, then the compiler could potentially optimize this loop to:

int cached_length = obj.length();
for (int i = 0; i < cached_length; ++i) {
   f(obj);
}

... because the fact that the function f does not modify the parameter guarantees that the length function should return the same values each time given that the object has not changed. However, if f is declared to take the parameter by a mutable reference, then length would need to be recomputed on each iteration of the loop, as f could have modified the object in a way to produce a change in the value.

As pointed out in the comments, this is assuming a number of additional caveats and would only be possible when invoking the compiler in a non-standard mode that allows it to make additional assumptions (such as that const methods are strictly a function of their inputs and that optimizations can assume that code will never use const_cast to convert a const reference parameter to a mutable reference).

like image 25
Michael Aaron Safyan Avatar answered Oct 18 '22 04:10

Michael Aaron Safyan


Function parameters:

const is not significant for referenced memory. It's like tying a hand behind the optimizer's back.

Suppose you call another function (e.g. void bar()) in foo which has no visible definition. The optimizer will have a restriction because it has no way of knowing whether or not bar has modified the function parameter passed to foo (e.g. via access to global memory). Potential to modify memory externally and aliasing introduce significant restrictions for optimizers in this area.

Although you did not ask, const values for function parameters does allow optimizations because the optimizer is guaranteed a const object. Of course, the cost to copy that parameter may be much higher than the optimizer's benefits.

See: http://www.gotw.ca/gotw/081.htm


Variable declarations: const int i = 1234

This depends on where it is declared, when it is created, and the type. This category is largely where const optimizations exist. It is undefined to modify a const object or known constant, so the compiler is allowed to make some optimizations; it assumes you do not invoke undefined behavior and that introduces some guarantees.

const int A(10);
foo(A);
// compiler can assume A's not been modified by foo

Obviously, an optimizer can also identify variables which do not change:

for (int i(0), n(10); i < n; ++i) { // << n is not const
 std::cout << i << ' ';
}

Function declarations: const char* foo()

Not significant. The referenced memory may be modified externally. If the referenced variable returned by foo is visible, then an optimizer could make an optimization, but that has nothing to do with the presence/absence of const on the function's return type.

Again, a const value or object is different:

extern const char foo[];

like image 7
justin Avatar answered Oct 18 '22 02:10

justin