why "const char &" as a parameter?

D

Darin Johnson

I keep running across that I'm maintaining that likes to define
function parameters as "const char &" or "const int &", etc.
Ie, constant reference parameters to a primitive type. This is
for normal functions, not operators.

I keep changing these to just have the plain old type, which
is more efficient (I'm using embedded systems) and less
obtuse. I'm puzzled why this one programmer insisted on
odd style everywhere. Maybe he's just applying a template
without thinking, as if it were like "const BigStruct &".
But I'm wondering if there's some school of thought out
there that encourages this and I'm missing something subtle.
 
J

Juha Nieminen

Darin said:
I keep changing these to just have the plain old type, which
is more efficient (I'm using embedded systems)

Did you check that your compiler is not already doing that
automatically for you?
 
R

Rolf Magnus

Juha said:
Did you check that your compiler is not already doing that
automatically for you?

If the function is expanded inline, this is highly likely, but for other
functions OTOH, it's rather not likely.
 
J

Jeff Schwab

Rolf said:
If the function is expanded inline, this is highly likely, but for other
functions OTOH, it's rather not likely.

That's exactly what I found. I assume it's because the compiler does
not yet know at the point of call whether the function (1) is defined in
some other translation to expect its arguments pass-by-reference, or (2)
will need to take the address of the argument.

Still, Juha's question was a good one.
 
J

Jeff Schwab

Darin said:
I keep running across that I'm maintaining that likes to define
function parameters as "const char &" or "const int &", etc.
Ie, constant reference parameters to a primitive type. This is
for normal functions, not operators.

I keep changing these to just have the plain old type, which
is more efficient

Have you checked that, or are you just assuming?
(I'm using embedded systems)

Excellent! If you really care about the low-level implementation of
argument passing, you need to get comfortable with your platform's
architecture and assembly language. It's not really on-topic here, but
I'm guessing I'm not the only one here who has worked at that level. At
worst, we can point you in the right direction.

and less obtuse.

ITYM "confusing to me."

I'm puzzled why this one programmer insisted on
odd style everywhere. Maybe he's just applying a template
without thinking, as if it were like "const BigStruct &".

He may indeed just want to pass arguments of primitive and user-defined
types consistently.

But I'm wondering if there's some school of thought out
there that encourages this and I'm missing something subtle.

Yes, there is. I have yet to see a compelling argument either for or
against.
 
P

Pavel

Darin said:
I keep running across that I'm maintaining that likes to define
function parameters as "const char &" or "const int &", etc.
Ie, constant reference parameters to a primitive type. This is
for normal functions, not operators.

I keep changing these to just have the plain old type, which
is more efficient (I'm using embedded systems) and less
obtuse. I'm puzzled why this one programmer insisted on
odd style everywhere. Maybe he's just applying a template
without thinking, as if it were like "const BigStruct &".
But I'm wondering if there's some school of thought out
there that encourages this and I'm missing something subtle.

It was already implicitly mentioned but before changing make sure the
functions do not use the address of the parameter; otherwise, the
behavior may change. Barring that, I am not aware of any drawbacks of
what you are doing -- as long as you know it gives your code an
advantage on your particular platform.

With the performance equal, I personally would still use by-value
convention because, for a prospective code reader, it results in less
tokens to scan and comprehend and less side effects to watch for.

If a parameter type is a template parameter, however, the whole
different can of worms should be considered. Unsure if it is relevant to
your question.

Hope this will help
-Pavel
 
G

Gerhard Fiedler

It was already implicitly mentioned but before changing make sure the
functions do not use the address of the parameter; otherwise, the
behavior may change. Barring that, I am not aware of any drawbacks of
what you are doing -- as long as you know it gives your code an
advantage on your particular platform.

Besides taking the address, there's always also the possibility to cast the
const away, isn't there? This then may also change the behavior.

Gerhard
 
D

Daniel T.

Gerhard Fiedler said:
Besides taking the address, there's always also the possibility to cast the
const away, isn't there? This then may also change the behavior.

Taking an address of the parameter or casting away constness would both
be dangerous...

void foo( const char& c ) {
// casting away constness would be undefined behavior and
// taking (and presumably saving) the address would be pointless.
}

int main() {
foo( '5' );
}
 
J

Johannes Bauer

Jeff said:
Have you checked that, or are you just assuming?

I just checked it, g++ 4.1.2 with x86-64 target.

x.cpp:
#include <stdio.h>

void foo(const int &lol) {
printf("%d\n", lol);
}

together with y.cpp:
void foo(const int &lol);

int main(int argc, char **argv) {
foo(123);
return 0;
}

i.e. two different modules, translated with -O3, yield this code:

400604: 48 8d 7c 24 14 lea 0x14(%rsp),%rdi
400609: c7 44 24 14 7b 00 00 movl $0x7b,0x14(%rsp)
400610: 00
400611: e8 0a 00 00 00 callq 400620 <_Z3fooRKi>

....

0000000000400620 <_Z3fooRKi>:
400620: 8b 37 mov (%rdi),%esi
400622: 31 c0 xor %eax,%eax
400624: bf 1c 07 40 00 mov $0x40071c,%edi
400629: e9 da fe ff ff jmpq 400508 <printf@plt>


While when using POD:

400604: bf 7b 00 00 00 mov $0x7b,%edi
400609: e8 12 00 00 00 callq 400620 <_Z3fooi>

....

0000000000400620 <_Z3fooi>:
400620: 89 fe mov %edi,%esi
400622: 31 c0 xor %eax,%eax
400624: bf 1c 07 40 00 mov $0x40071c,%edi
400629: e9 da fe ff ff jmpq 400508 <printf@plt>


So, really, there is one indirection more with the const int& style -
the question is: why? I guess it's the ABI which would break? In any
case the direction in the called function should only need to be
performed once. I wonder if there is some magic
-fbreak-convention-for-optimization flag which would optimize the code
in that way. Any other people who can test it? Its an interesting
problem... I'd have assumed that it would result in the same code.

Kind regards,
Johannes
 
D

Darin Johnson

Yes, there is. I have yet to see a compelling argument either for or
against.

Ok, thanks for replies everyone. I had checked the
compiler for PowerPC and it does use extra indirections
when used this way instead of optimizing it away.
(2 indirections, since the caller also has to put stuff
that would normally be in registers on the PowerPC
onto the stack first)

None of the code takes the address of the paramters,
and the functions aren't templated. I normally just
leave it alone, unless I've got the files checked out
and am modifying them anyway.

I had seen other styles that seemed "odd" until
others explained the reasoning behind them, and
wondered if this might be one of them.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top