Skip to contentSkip to conversation

efficiency in passing a value to a function

DISCUSSION Shriramana Sharma 5 participants 11 messages Apr 4, 2007 – Apr 14, 2007

lore
Share & tools
lore
#0 lore raw

Hello.

Is providing an input to a function by constant reference more efficient than passing it by value? In what way.

For ex:

int addOne ( const & int inValue ) { return inValue + 1 ; }

vs:

int addOne ( int inValue ) { return inValue + 1 ; }

or:

void printThis ( const & int inValue ) { cout << inValue ; }

vs:

void printThis ( int inValue ) { cout << inValue ; }

I think passing as const & would be more efficient since passing by value would involve copying the value whereas passing by const & would skip this step. Am I right? Or is there something else?

Thanks in advance.

Shriramana Sharma.

#1 lore raw
Quoted 2 lines · Shriramana Sharma

Is providing an input to a function by constant reference more efficient than passing it by value? In what way.

Passing a reference doesn't copy the value. This can be significant if the value is large (i.e. a structure); for values which are no larger than a pointer, it is unlikely to make any difference.

Signature · 1 line
Glynn Clements <[email protected]>
#2 lore raw
Quoted 7 lines · Glynn Clements
Quoted 2 lines · Shriramana Sharma

Is providing an input to a function by constant reference more efficient than passing it by value? In what way.

Passing a reference doesn't copy the value. This can be significant if the value is large (i.e. a structure); for values which are no larger than a pointer, it is unlikely to make any difference.

For values which are not larger than a pointer, passing by reference can be even (slightly) slower, because the pointer must be dereferenced in the function in order to use the value:

void f1(const int v)

{
    printf("%d", v);
}

void f2(const int & v)

{
    printf("%d", v);
}

Compiled with -O2:

(gdb) disas f1
Dump of assembler code for function _Z2f1i:

0x08048460 <_Z2f1i+0>:  push   %ebp
0x08048461 <_Z2f1i+1>:  mov    %esp,%ebp
0x08048463 <_Z2f1i+3>:  sub    $0x10,%esp
0x08048466 <_Z2f1i+6>:  mov    0x8(%ebp),%eax
0x08048469 <_Z2f1i+9>:  push   %eax
0x0804846a <_Z2f1i+10>: push   $0x80485d4
0x0804846f <_Z2f1i+15>: call   0x8048358 <printf@plt>

0x08048474 <_Z2f1i+20>: leave
0x08048475 <_Z2f1i+21>: ret
End of assembler dump.
(gdb) disas f2
Dump of assembler code for function _Z2f2RKi:

0x08048480 <_Z2f2RKi+0>:        push   %ebp
0x08048481 <_Z2f2RKi+1>:        mov    %esp,%ebp
0x08048483 <_Z2f2RKi+3>:        sub    $0x10,%esp
0x08048486 <_Z2f2RKi+6>:        mov    0x8(%ebp),%eax
0x08048489 <_Z2f2RKi+9>:        mov    (%eax),%edx      //pointer dereference
0x0804848b <_Z2f2RKi+11>:       push   %edx
0x0804848c <_Z2f2RKi+12>:       push   $0x80485d4
0x08048491 <_Z2f2RKi+17>:       call   0x8048358 <printf@plt>
0x08048496 <_Z2f2RKi+22>:       leave
0x08048497 <_Z2f2RKi+23>:       ret

End of assembler dump.

Adam

#3 lore raw
In reply to Shriramana Sharma

Shriramana,

Quoted 17 lines · Shriramana Sharma

Hello.

Is providing an input to a function by constant reference more efficient than passing it by value? In what way.

For ex:

int addOne ( const & int inValue ) { return inValue + 1 ; }

vs:

int addOne ( int inValue ) { return inValue + 1 ; }

or:

void printThis ( const & int inValue ) { cout << inValue ; }

Quoted 7 lines

vs:

void printThis ( int inValue ) { cout << inValue ; }

I think passing as const & would be more efficient since passing by value would involve copying the value whereas passing by const & would skip this step. Am I right? Or is there something else?

I have seen many programs making use const reference parameters in order to inform the compiler that the parameter is read-only, and hence should be better optimized.

Unfortunately, this intent is at odds with the C++ language definition. The const keyword says that the storage may not be modified through the given name. What it does not say is that the storage cannot be modified through some other name.

With the exception of variables directly declared const, which means you can only initialize them, const is basically ineffective a improving run-time performance. It does, however, catch errors in the programming process.

\Steve

--

Steve Grägert <[email protected]>
Jabber xmpp://[email protected]
Internet http://eth0.graegert.com, http://blog.graegert.com
-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw
Quoted 13 lines · Steve Graegert
Quoted 3 lines

I think passing as const & would be more efficient since passing by value would involve copying the value whereas passing by const & would skip this step. Am I right? Or is there something else?

I have seen many programs making use const reference parameters in order to inform the compiler that the parameter is read-only, and hence should be better optimized.

Unfortunately, this intent is at odds with the C++ language definition. The const keyword says that the storage may not be modified through the given name. What it does not say is that the storage cannot be modified through some other name.

Quoted 4 lines

With the exception of variables directly declared const, which means you can only initialize them, const is basically ineffective a improving run-time performance. It does, however, catch errors in the programming process.

Using a const qualifier still allows the compiler to optimise the caller. E.g. if it computes a complex expression involving a variable, passes a pointer/reference to that variable to a function, then subsequently uses the result of the expression, it doesn't have to re-compute the expression if the pointer/reference has a const qualifier.

In any case, I suspect that the OP was talking primarily about passing references rather than values, rather than about const qualifiers per se.

Signature · 1 line
Glynn Clements <[email protected]>
#5 lore raw
Quoted 28 lines · Glynn Clements
Quoted 13 lines · Steve Graegert
Quoted 3 lines

I think passing as const & would be more efficient since passing by value would involve copying the value whereas passing by const & would skip this step. Am I right? Or is there something else?

I have seen many programs making use const reference parameters in order to inform the compiler that the parameter is read-only, and hence should be better optimized.

Unfortunately, this intent is at odds with the C++ language definition. The const keyword says that the storage may not be modified through the given name. What it does not say is that the storage cannot be modified through some other name.

Quoted 4 lines

With the exception of variables directly declared const, which means you can only initialize them, const is basically ineffective a improving run-time performance. It does, however, catch errors in the programming process.

Using a const qualifier still allows the compiler to optimise the caller. E.g. if it computes a complex expression involving a variable, passes a pointer/reference to that variable to a function, then subsequently uses the result of the expression, it doesn't have to re-compute the expression if the pointer/reference has a const qualifier.

Quoted 3 lines

In any case, I suspect that the OP was talking primarily about passing references rather than values, rather than about const qualifiers per se.

This might indeed be true.

If a programmer has chosen to pass a reference rather than a value, even if no reference is actually required, intentions to improve run-time performance come into mind. It is much more intuitive to pass primitives by value and use references only where appropriate, since performance gains due to the use of the const qualifier are very small and negligible in most cases.

\Steve

--

Steve Grägert <[email protected]>
Jabber xmpp://[email protected]
Internet http://eth0.graegert.com, http://blog.graegert.com
-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#6 lore raw
Quoted 6 lines · Steve Graegert

If a programmer has chosen to pass a reference rather than a value, even if no reference is actually required, intentions to improve run-time performance come into mind. It is much more intuitive to pass primitives by value and use references only where appropriate, since performance gains due to the use of the const qualifier are very small and negligible in most cases.

I am somewhat confused. As I see it, the usage of a const ref for passing a parameter by reference is to improve runtime performance, yes, but it is not through the "const" part of it. It is through the reference part of it, which avoids a copy of the parameter being constructed which can be costly with large classes or structs. The const part of it is only there to prevent the function from modifying the source data, whether intentionally or accidentally. There may be a side-effect of optimization, but at least to my understanding the intent of const here is making the source read-only. Is this understanding wrong?

I agree of course that in case of tiny tidbits of parameters like a few int-s, double-s or even std::string-s, there is not much meaning in using const ref-s, and it is more intuitive to pass these by value. It is only practically useful to pass big classes / struct-s by reference.

Shriramana Sharma.

#7 lore raw
Quoted 7 lines · Shriramana Sharma
Quoted 6 lines

If a programmer has chosen to pass a reference rather than a value, even if no reference is actually required, intentions to improve run-time performance come into mind. It is much more intuitive to pass primitives by value and use references only where appropriate, since performance gains due to the use of the const qualifier are very small and negligible in most cases.

Quoted 9 lines

I am somewhat confused. As I see it, the usage of a const ref for passing a parameter by reference is to improve runtime performance, yes, but it is not through the "const" part of it. It is through the reference part of it, which avoids a copy of the parameter being constructed which can be costly with large classes or structs. The const part of it is only there to prevent the function from modifying the source data, whether intentionally or accidentally. There may be a side-effect of optimization, but at least to my understanding the intent of const here is making the source read-only. Is this understanding wrong?

The const is primarily for correctness (ensuring that the callee doesn't modify the data), but there may also be a performance gain.

Signature · 1 line
Glynn Clements <[email protected]>
#8 lore raw
In reply to Shriramana Sharma
Quoted 4 lines · Shriramana Sharma

I agree of course that in case of tiny tidbits of parameters like a few int-s, double-s or even std::string-s, there is not much meaning in using const ref-s, and it is more intuitive to pass these by value. It is only practically useful to pass big classes / struct-s by reference.

Well, std::string should be passed by const reference. Depending on the implementation, passing std::string by value may involve heap allocation/deallocation and memory copy operations which are quite costly.

Adam

#9 lore raw
In reply to Steve Graegert
Quoted 3 lines · Steve Graegert

I have seen many programs making use const reference parameters in order to inform the compiler that the parameter is read-only, and hence should be better optimized.

I thought the usage of const before & in function definitions was to prevent the value from being modified. I never knew there is an optimization aspect.

Quoted 4 lines

Unfortunately, this intent is at odds with the C++ language definition. The const keyword says that the storage may not be modified through the given name. What it does not say is that the storage cannot be modified through some other name.

I observe that this is true for C too, not just C++. Anyway, how is it exactly "at odds" with the language definition?

[BTW gcc is intelligent enough to give me a compile-time warning:

const.c:7: warning: initialization discards qualifiers from pointer target type

when I write const int i = 2 ; int * iptr = & i ; and I don't even have to give -Wall !]

Quoted 3 lines

you can only initialize them, const is basically ineffective a improving run-time performance. It does, however, catch errors in the programming process.

const is also useful for preventing a function writing to a variable passed to it as reference, which is what this thread was originally about.

Just for the record, are there any other uses for const?

Shriramana Sharma.

#10 lore raw
Quoted 7 lines · Shriramana Sharma
Quoted 3 lines

I have seen many programs making use const reference parameters in order to inform the compiler that the parameter is read-only, and hence should be better optimized.

I thought the usage of const before & in function definitions was to prevent the value from being modified. I never knew there is an optimization aspect.

There is, but it's usually secondary. Also, it's more likely that it will enable optimisation in the caller than in the callee.

Quoted 7 lines
Quoted 4 lines

Unfortunately, this intent is at odds with the C++ language definition. The const keyword says that the storage may not be modified through the given name. What it does not say is that the storage cannot be modified through some other name.

I observe that this is true for C too, not just C++. Anyway, how is it exactly "at odds" with the language definition?

The fact that a const-qualified object may change eliminates many possibilities for optimisation.

This is why the ANSI C standard includes certain rules regarding "aliasing" (where several different expressions may actually refer to the same region of memory).

These rules permit a compiler to assume that:

1. A value or array referenced by a pointer doesn't overlap a global variable.

2. Primitive (non-struct/union) objects of different types don't overlap.

E.g. consider the following code:

	int foo(int *p)
	{
		int x = globalvar++;
		int y = *p;
		return x * y;
	}

If it wishes, the compiler can swap the order in which x and y are evaluated. Rule #1 above means that it doesn't have to consider the possibility of being called as foo(&globalvar), where the globalvar++ would change the value of *p.

Without aliasing rules, many potential optimisations would have to be foregone in case what appear to be distinct objects share the same memory.

However, the aliasing rules state that the compiler cannot assume that objects which are of the same type and which are both referenced through pointers cannot overlap. So in the case of:

	int foo(int *p, int *q)
	{
		int x = (*p)++;
		int y = *q;
	}

the compiler cannot re-order the assignments because *p++ might modify *q (if p == q).

If you write "clean" code, you don't need to worry about aliasing.

Problems normally arise through the use of "type punning", where you treat a specific area of memory as having two different types. E.g.

	union int_bytes {
		int i;
		unsigned char b[4];
	};

	...

	union int_bytes tmp;
	unsigned char lo_byte;

	tmp.i = 12345;
	lo_byte = tmp.b[0];

The above code may work fine when optimisation is disabled, but fail when it is enabled.

This type of code is inevitably non-portable, as you are making assumptions about the way in which specific types are stored in memory.

This kind of "trick" is most common in low-level code which sacrifices portability (and legibility) for performance. A good example is the Linux kernel. This the main reason why it used to be quite common that you had to use an older version of gcc to compile the kernel: because newer versions optimised more aggressively, and thus were more likely to break code which ignored the aliasing rules.

Quoted 8 lines

[BTW gcc is intelligent enough to give me a compile-time warning:

const.c:7: warning: initialization discards qualifiers from pointer target type

when I write const int i = 2 ; int * iptr = & i ; and I don't even have to give -Wall !]

Quoted 8 lines
Quoted 3 lines

you can only initialize them, const is basically ineffective a improving run-time performance. It does, however, catch errors in the programming process.

const is also useful for preventing a function writing to a variable passed to it as reference, which is what this thread was originally about.

Just for the record, are there any other uses for const?

It enables certain optimisations, mostly in the caller. E.g. the code:

	y = x * 2;
	foo(&x);
	return y;

can be re-arranged as:

	foo(&x);
	y = x * 2;
	return y;

if foo is declared "void foo(const int *)" but not if it is declared as "void foo(int *)", as the former is guaranteed not to modify x, but the latter isn't.

Conversely, the "volatile" qualifier disables certain optimisations.

Neither "const" nor "volatile" were present in the original K&R C language. They were added to the ANSI C standard specifically to deal with issues related to optimisation.

Signature · 1 line
Glynn Clements <[email protected]>