value vs. const ref, char* vs char[4]

C

CubsNo1

Good morning.

I am disturbed by discovering that passing arguments by value and by
const reference is treated the same by the Gnu and the Sun compilers/
linkers. Also, passing an argument of char* and passing an argument
of char[4] are not distinguished. This is especially disturbing when
you mix in templates.

I haven't been able to get my question answered by reading my favorite
author Bruce Eckel (sal-lute!) and I haven't been able to find the
salient part of the standard. Can someone point me to a nice writeup
on this topic?


Regards,

Abraham
 
T

tragomaskhalos

Good morning.

I am disturbed by discovering that passing arguments by value and by
const reference is treated the same by the Gnu and the Sun compilers/
linkers.  Also, passing an argument of char* and passing an argument
of char[4] are not distinguished.  This is especially disturbing when
you mix in templates.

With regards to the first point, it seems reasonable to me
for a compiler to produce the same code for
/void foo(const int&);/ as for /void foo(int);/.
Is this what you meant? If so, what problems do you
foresee?

Wrt char* vs char[4], I don't see a problem either; in
ordinary argument passing, the array decays to the pointer.
For template argument deduction the array-ness is respected,
eg this array length function works as expected:
template <typename T, int N>
int arraySize (const T(&)[N]) { return N; }
 
P

Pete Becker

With regards to the first point, it seems reasonable to me
for a compiler to produce the same code for
/void foo(const int&);/ as for /void foo(int);/.

It certainly doesn't seem reasonable to me. They have different
semantics. The int argument is modifiable inside foo, but the const
int& argument is not.
 
T

tragomaskhalos

It certainly doesn't seem reasonable to me. They have different
semantics. The int argument is modifiable inside foo, but the const
int& argument is not.

Yes sorry, I didn't mean the function body, I meant the argument
passing code at the call site; eg push a value onto the stack
in both cases. I interpreted the OP's confusion to be that he
expected /void foo(const int&);/ to produce the same *calling*
code as /void foo(int*);/, whereas my point was that a reference
needn't necessarily be treated this way. Does this make sense,
or have I dug myself a deeper hole? :)
 
E

Erik Wikström

Good morning.

I am disturbed by discovering that passing arguments by value and by
const reference is treated the same by the Gnu and the Sun compilers/
linkers.

How exactly are they treated the same? They certainly will have
different semantics when used so the compiler must produce different
code for them. Can you provide any examples to illustrate your point?
 
A

Andrew Koenig

Yes sorry, I didn't mean the function body, I meant the argument
passing code at the call site; eg push a value onto the stack
in both cases. ... Does this make sense,
or have I dug myself a deeper hole? :)

You have dug yourself a deeper hole:

#include <iostream>

int foo;

int f(int x) { foo = 123; return x; }

int g(const int& x) { foo = 123; return x; }

int main()
{
foo = 456;
std::cout << f(foo) << std::endl; // prints 456
foo = 456;
std::cout << g(foo) << std::endl; // prints 123
}
 
D

Daniel T.

I am disturbed by discovering that passing arguments by value and by
const reference is treated the same by the Gnu and the Sun compilers/
linkers.

I take this to be a complaint that the compiler doesn't distinguish
between:

void foo( const int& );

and

void foo( int );

When deciding which override to call.
Also, passing an argument of char* and passing an argument
of char[4] are not distinguished. This is especially disturbing when
you mix in templates.

And I take this to be a complaint that the compiler considers this an
illegal override:

void foo( char* a );
void foo( char a[] );

If I'm right in my interpretation, why do you find this so disturbing?
If I'm wrong, then what do you mean?
I haven't been able to get my question answered by reading my favorite
author Bruce Eckel (sal-lute!) and I haven't been able to find the
salient part of the standard. Can someone point me to a nice writeup
on this topic?

Maybe if you posted some relevant code?
 
A

Andrey Tarasevich

...
I am disturbed by discovering that passing arguments by value and by
const reference is treated the same by the Gnu and the Sun compilers/
linkers.

Internally replacing a 'const T&' parameter with a 'T' parameter is
possible if the compiler is smart enough to determine that the
parameter's value is not modified inside the function and that the
parameter's "address identity" is not playing any important role inside
the function. In that case internal transformation of 'const T&'
parameter into 'T' parameter can be useful as a compiler optimization.

In general case such a transformation is not possible, since, for
example, the function might cast away the constness of the reference and
legally modify the referenced object, which obviously will not produce
the required effect in case when reference parameter is replaced with a
"value" parameter.
Also, passing an argument of char* and passing an argument
of char[4] are not distinguished. This is especially disturbing when
you mix in templates.

You mean parameters of these two types produce the same passing code? Of
course they do, since in function parameter declarations array types
decay to pointer types, even when they are supplied with concrete sizes.
 
T

tragomaskhalos

    #include <iostream>
    int foo;
    int f(int x) { foo = 123; return x; }

    int g(const int& x) { foo = 123; return x; }

    int main()
    {
        foo = 456;
        std::cout << f(foo) << std::endl;        // prints 456
        foo = 456;
        std::cout << g(foo) << std::endl;        // prints 123
    }

Ouch, yes, very nasty.
Reading Andrey Tarasevich's response else-thread,
it seems that something like a simple inline
setter method with a 'const int&' argument could
be safely 'int-ed' (which scarcely counts), but
anything more complicated would be fraught with
problems. Which begs the question, what did the OP
observe with the Gnu/Sun tools to prompt his
question ?!
 
A

Andrey Tarasevich

tragomaskhalos said:
Which begs the question, what did the OP
observe with the Gnu/Sun tools to prompt his
question ?!

There's might be another reason to do something like that (although I'm
just guessing here): the compiler might've decided to generate two
separate bodies for the same [small, single-parameter] function: one
with reference parameter - to call in cases when the supplied argument
is an lvalue, and another with value parameter - when it is not. The OP
might've been observing the call to the latter. Of course, without more
details from the OP we can only guess what was happening.
 
R

Rick

Sorry to be out of the loop for a while. Here is one thing that's
bothering me:


#include <iostream>

using namespace std;

template<typename T> bool fun(const T& value) {
cout << "In fun(const T&);" << endl;
}

template<typename T> bool fun(T value) {
cout << "In fun(T);" << endl;
}

int main(int argc, char** argv) {
fun(static_cast<const int&>(10) );
}


$ CC test.C
"test.C", line 14: Error: Overloading ambiguity between
"fun<int>(const int&)" and "fun<int>(int)".
1 Error(s) detected.
$
$
$ g++ test.C
test.C: In function `int main(int, char**)':
test.C:14: error: call of overloaded `fun(const int&)' is ambiguous
test.C:5: note: candidates are: bool fun(const T&) [with T = int]
test.C:9: note: bool fun(T) [with T = int]
$


I would have said that if I tell the compiler explicitly that I want a
const int&, there is no ambiguity. Something in the C++ standard
apparently says that this is correct behavior, but it seems wrong to
me.


Regards,

Abraham
 

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

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,201
Latest member
KourtneyBe

Latest Threads

Top