Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What's the point of passing parameter by value (vs. const ref)

4 views
Skip to first unread message

Martin T.

unread,
Jul 2, 2008, 1:58:01 PM7/2/08
to
Hi all.

When writing new C++ code, what is the point of passing any (input)
parameter by value when passing by const reference will just work as
well? (Even and especially PODs, I would not do it with a complex type
anyway.)
(Given that in 90% of the code you will never want to modify the
parameter anyway.)

br,
Martin

[EXAMPLE_CODE]
class foo {
};

void f_val_int(int);
void f_ref_int(const int&);
void f_val_foo(foo);
void f_ref_foo(const foo&);

int main(int,)
{
double d = 1.2;
f_val_int(d);
f_ref_int(d);
f_val_int(1.4);
f_ref_int(1.5);

foo x;
f_val_foo(x);
f_ref_foo(x);
f_val_foo(foo());
f_ref_foo(foo());

return 0;
};

void f_val_int(const int x) {
int y = x;
y++;
}

void f_ref_int(const int& x) {
int y = x;
y++;
}

void f_val_foo(const foo f) {
foo ff = f;
ff;
}

void f_ref_foo(const foo& f) {
foo ff = f;
ff;
}
[/EXAMPLE_CODE]

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Jim Langston

unread,
Jul 3, 2008, 4:27:25 AM7/3/08
to

"Martin T." <0xCDC...@gmx.at> wrote in message
news:g4ferd$sji$1...@registered.motzarella.org...

> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
> (Given that in 90% of the code you will never want to modify the
> parameter anyway.)

1. Passing an interger by value is usually faster than passing an integer by
reference.
2. Passing a paramater by value allows modification of the paramater as a
local variable I.E.

void Reverse( const char* CString, int length )
{
while ( --length )
{
std::cout << CString[length];
}
}

3. A lot of existing C code passes by value.
4. Sometimes it is clearer to pass by value rather than by reference. I
once toyed with changing all pointer paramters in a program to references
and some code got jsut downright ugly.
5. Choice
6+ Reasons I haven't thought of

Eric Johnson

unread,
Jul 3, 2008, 4:28:17 AM7/3/08
to
On Jul 2, 10:58 am, "Martin T." <0xCDCDC...@gmx.at> wrote:
> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)

<snip>

In theory, passing a small type (int, char, float, etc) by value will
be more efficient than passing by const reference. In your example
function "f_ref_int", the address of the int gets passed to the
function and then the value of "x" has to be fetched, whereas in
f_val_int, the value of "x" is passed directly.

In practice, it's hard to say if one would see much performance
difference without taking some measurements.

-Eric

Hak...@gmail.com

unread,
Jul 3, 2008, 4:33:08 AM7/3/08
to
> ...what is the point of passing any (input)

> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)

Well, for the POD's, or any complex data type (I don't know what a POD
is), a copy constructor should make passing by const reference and
value irrelevant...well, short of efficiency.

mtl...@gmail.com

unread,
Jul 3, 2008, 5:28:03 AM7/3/08
to

{ Edits: quoted clc++m banner removed, since it's available at the end of this
article (and indeed, every clc++m article). There's no need to quote it. -mod }

It is because passing by reference/pointer will introduce the alias
problem, which hinder the compiler to perform a numbers of
optimizations.
Therefore, in a performance point of view, primitive types should pass
by value while large data structure should pass by reference/pointer.
More information on the aliasing problem:
http://www.ddj.com/cpp/184404273;jsessionid=FAZXOZJKL5K24QSNDLPCKHSCJUNN2JVN?_requestid=161084

werasm

unread,
Jul 3, 2008, 5:28:02 AM7/3/08
to

Martin T. wrote:
> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
> (Given that in 90% of the code you will never want to modify the
> parameter anyway.)

Whether passing by const reference or value, for the
callers perspective the value is not modified.

Wrt. to your question, typically I would think that passing
a builtin type by reference or const ref would cause
an unecessary level of indirection, whereas passing by
value does not cause this. Furthermore you gain nothing
when passing by const reference as opposed to passing
by value in terms of what is copied.

Therefore, passing by value the builtin type you would
gain at least the lack of indirection.

Regards,

Werner

Erik Wikström

unread,
Jul 3, 2008, 5:28:01 AM7/3/08
to
On 2008-07-02 19:58, Martin T. wrote:
> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
> (Given that in 90% of the code you will never want to modify the
> parameter anyway.)

Speed, for small types passing by value is just as fast as passing the
reference, and you do not have to pay a penalty when accessing it (a
reference is usually implemented like a pointer, so you have one lever
of indirection when accessing it).

Also, if you need a copy in the function (you can not operate on the
original object) you might as well create the copy when you call the
function instead of inside the function.

--
Erik Wikström

Le Chaud Lapin

unread,
Jul 3, 2008, 5:28:02 AM7/3/08
to
On Jul 2, 12:58 pm, "Martin T." <0xCDCDC...@gmx.at> wrote:
> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
> (Given that in 90% of the code you will never want to modify the
> parameter anyway.)

Efficiency.

> void f_val_int(const int x) {
> int y = x;
> y++;
>
> }

...results in thing whose size is sizeof(int) being copied to the
stack. Kein Problem.

>
> void f_ref_int(const int& x) {
> int y = x;
> y++;
>
> }

...effectively results in thing whose size is sizeof(int *) being
copied to the stack. That thing is a pointer that has to be derefenced
to get at x, theoretically causing a slight performance penalty.

> void f_val_foo(const foo f) {
> foo ff = f;
> ff;
>
> }

...results in a thing whose size is sizeof(foo) being copied to stack.
If sizeof(foo) is large number, this is obviously not good. An
unnecessary expenditure of stack memory and CPU time.

> void f_ref_foo(const foo& f) {
> foo ff = f;
> ff;}
>

Best code for passing read-only aggregates, IMHO.

-Le Chaud Lapin-

red floyd

unread,
Jul 3, 2008, 5:28:02 AM7/3/08
to
On Jul 2, 10:58 am, "Martin T." <0xCDCDC...@gmx.at> wrote:

1. It's a C legacy.
2. You may want to change the (copied) value of your parameter inside
the function. e.g.

void f(int n)
{
while (n-- > 0)
{
// do something

Pavel Minaev

unread,
Jul 3, 2008, 5:28:03 AM7/3/08
to

When you receive a parameter by reference, you should keep in mind
that the actual value which is referenced can be changed by other code
- it may be const for you, but it is not necessarily const for
everyone else. Most often you don't care, but sometimes it might
matter - and in that case you need to have a copy.

Of course, there are performance reasons, too - when you get an const
int&, the compiler is much less likely to generate efficient register-
only code than for plain int - again, this is mostly because the value
referenced might be changed from other code you call. For inline
functions, a decent compiler will be able to optimize away the
references where it does not change the semantics of the function, but
I've yet to see one that can do that trick for non-inline functions,
and particularly for virtual functions.

Marcin.B...@yahoo.com

unread,
Jul 3, 2008, 10:51:53 AM7/3/08
to
On Jul 2, 10:58 am, "Martin T." <0xCDCDC...@gmx.at> wrote:
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
> (Given that in 90% of the code you will never want to modify the
> parameter anyway.)

References are implemented as pointers, so whenever you use a
reference parameter in your functions, two readings are performed:
value of a pointer to the passed variable and the variable itself.
As copy-constructors of built-in types are cheap, it's usually more
efficient to pass them by value. The same applies to STL iterators.
For all other types passing by const reference is preferable.

Regards,
Marcin Barczynski

Francis Glassborow

unread,
Jul 3, 2008, 10:56:04 AM7/3/08
to
Pavel Minaev wrote:

>
> When you receive a parameter by reference, you should keep in mind
> that the actual value which is referenced can be changed by other code
> - it may be const for you, but it is not necessarily const for
> everyone else. Most often you don't care, but sometimes it might
> matter - and in that case you need to have a copy.
>

And there are massive implications when dealing with multiple threads of
concurrency. Both of these will be part of the new C++ Standard.


--
Note that robinton.demon.co.uk addresses are no longer valid.

Michael DOUBEZ

unread,
Jul 3, 2008, 10:52:44 AM7/3/08
to
Martin T. a écrit :

> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
> (Given that in 90% of the code you will never want to modify the
> parameter anyway.)

In is true that const reference allows passing parameters with input
mode semantic but it usually requires deferencing in the function.

So it depends, in theory:
- pass-by-value requires additional storage but data is on the stack
which means it is likely to be in the cache and accesses are faster.
- pass-by-reference allows to pass only an alias (saving a copy) but
may be slower is some specific cases because reads use address.

Personally, I have never seen a case were this was an issue and my rule
of thumb is pass-by-value for scalar and small POD and
pass-by-const-reference for more complex data.

Does anyone know the impact of c++0x memory model on this issue: is the
data passed by const reference likely to be put in cache or is it
fetched each time to allow concurrent read/write ?

--
Michael

Andrew Koenig

unread,
Jul 3, 2008, 11:58:01 AM7/3/08
to
"Martin T." <0xCDC...@gmx.at> wrote in message
news:g4ferd$sji$1...@registered.motzarella.org...

> When writing new C++ code, what is the point of passing any (input)


> parameter by value when passing by const reference will just work as
> well?

One possibility is that you might be mistaken about whether it works just as
well.

Here's an example:

// Divide all the elements of a vector<double> by a constant
void vec_divide(vector<double>& v, const double& x)
{
for (vector<double>::iterator it = v.begin(); it != v.end(); ++it)
*it /= x;
}

Now consider what happens when you call

vector<double> v;
v.push_back(1.23);
v.push_back(4.56);
vec_divide(v, v[0]);

If you don't see the problem, try running it.

JohnMcG

unread,
Jul 3, 2008, 5:45:38 PM7/3/08
to
On Jul 2, 12:58 pm, "Martin T." <0xCDCDC...@gmx.at> wrote:
> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)


This probably goes under the category of "guarding against
Machiavelli", but with pass by value, you know that the program
doesn't pull chicanery like this...

void foo(const T& in)
{
const_cast<T&>(in) = newVal;
}

John McG.

Mathias Gaunard

unread,
Jul 3, 2008, 5:47:07 PM7/3/08
to
On 3 juil, 11:28, mtl...@gmail.com wrote:

> It is because passing by reference/pointer will introduce the alias
> problem, which hinder the compiler to perform a numbers of
> optimizations.

Also, I do not know whether it is related, but I've observed than when
a function takes a reference to a T and that I'm passing to it a T
lvalue which is part of another object, optimizers keep the object
alive even if it is not needed.
While that is indeed needed for pointers, it isn't for references.
That certainly penalizes generated code for nothing.

Deane Yang

unread,
Jul 3, 2008, 5:45:13 PM7/3/08
to
{ Top-posting is strongly discouraged in this group. Please do not top-post. -mod }

Wow. That scares the heck out of me. Are there programming guidelines
that would help me avoid or spot such an error when coding?

Jacky Goyon

unread,
Jul 4, 2008, 9:25:39 PM7/4/08
to
"Andrew Koenig" <a...@acm.org> a écrit dans le message de
news:G94bk.91687$102....@bgtnsc05-news.ops.worldnet.att.net...

> "Martin T." <0xCDC...@gmx.at> wrote in message
> news:g4ferd$sji$1...@registered.motzarella.org...
>
> > When writing new C++ code, what is the point of passing any (input)
> > parameter by value when passing by const reference will just work as
> > well?
>
> One possibility is that you might be mistaken about whether it works just
as
> well.
>
> Here's an example:
>
> // Divide all the elements of a vector<double> by a constant
> void vec_divide(vector<double>& v, const double& x)
> {
> for (vector<double>::iterator it = v.begin(); it != v.end();
++it)
> *it /= x;
> }
>
> Now consider what happens when you call
>
> vector<double> v;
> v.push_back(1.23);
> v.push_back(4.56);
> vec_divide(v, v[0]);
>
> If you don't see the problem, try running it.
good example !
another one:
#include <iostream>
void f(int * p, const int & x)
{
++(*p);
}

int main(int argc, char *argv[]) {
int x=1;
int * p=&x;
f(p,x);
std::cout<<x;
return 0;

Martin T.

unread,
Jul 5, 2008, 5:58:01 AM7/5/08
to
Andrew Koenig wrote:
> "Martin T." <0xCDC...@gmx.at> wrote in message
> news:g4ferd$sji$1...@registered.motzarella.org...
>
>> When writing new C++ code, what is the point of passing any (input)
>> parameter by value when passing by const reference will just work as
>> well?
>
> One possibility is that you might be mistaken about whether it works just as
> well.
>
> Here's an example:
>
> // Divide all the elements of a vector<double> by a constant
> void vec_divide(vector<double>& v, const double& x)
> {
> for (vector<double>::iterator it = v.begin(); it != v.end(); ++it)
> *it /= x;
> }
>
> Now consider what happens when you call
>
> vector<double> v;
> v.push_back(1.23);
> v.push_back(4.56);
> vec_divide(v, v[0]);
>
> If you don't see the problem, try running it.
>
>

Heh. I Admit I have not seen the problem :)

Given that this kind of problem would exist for any type and that for
complex types one would in general pass by reference, ... under what
headline would this kind of problem be discussed? I'm sure there are
some more interesting examples (std? boost?) out there where the problem
has been addressed - what would I google for? Is there a name for this
problem class?

cheers,
Martin

Martin Bonner

unread,
Jul 5, 2008, 6:58:04 AM7/5/08
to
On Jul 3, 10:45 pm, Deane Yang <deane.y...@yahoo.com> wrote:
>
> Andrew Koenig wrote:
> > "Martin T." <0xCDCDC...@gmx.at> wrote in message

> >news:g4ferd$sji$1...@registered.motzarella.org...
>
> >> When writing new C++ code, what is the point of passing any (input)
> >> parameter by value when passing by const reference will just work as
> >> well?
>
> > One possibility is that you might be mistaken about whether it works just as
> > well.
>
> > Here's an example:
>
> > // Divide all the elements of a vector<double> by a constant
> > void vec_divide(vector<double>& v, const double& x)
> > {
> > for (vector<double>::iterator it = v.begin(); it != v.end(); ++it)
> > *it /= x;
> > }
>
> > Now consider what happens when you call
>
> > vector<double> v;
> > v.push_back(1.23);
> > v.push_back(4.56);
> > vec_divide(v, v[0]);
>
> > If you don't see the problem, try running it.
>
> Wow. That scares the heck out of me. Are there programming guidelines
> that would help me avoid or spot such an error when coding?

Avoid pass by reference? Don't modify your arguments? Write plenty
of unit tests?

David Abrahams

unread,
Jul 6, 2008, 6:33:35 PM7/6/08
to

on Thu Jul 03 2008, Marcin.Barczynski-AT-yahoo.com wrote:

> On Jul 2, 10:58 am, "Martin T." <0xCDCDC...@gmx.at> wrote:
>> When writing new C++ code, what is the point of passing any (input)
>> parameter by value when passing by const reference will just work as
>> well? (Even and especially PODs, I would not do it with a complex type
>> anyway.)
>> (Given that in 90% of the code you will never want to modify the
>> parameter anyway.)
>
> References are implemented as pointers, so whenever you use a
> reference parameter in your functions, two readings are performed:
> value of a pointer to the passed variable and the variable itself.
> As copy-constructors of built-in types are cheap, it's usually more
> efficient to pass them by value. The same applies to STL iterators.
> For all other types passing by const reference is preferable.

Not necessarily. For example, try running the program below. With my
compiler it prints the following

default ctor
=== by reference ===
default ctor
copy ctor
swap
dtor
dtor
=== by value ===
default ctor
swap
dtor
=== done ===
dtor

which demonstrates that passing by reference can cause twice as many
copies as passing by value when the source is an rvalue. That can
really add up when the source is expensive to copy like a
vector<string>. If you're going to copy the argument anyway, you're far
better off passing it by value and swapping it into position. That
allows the compiler to elide the copy used to create the parameter value
(inside the function) when the argument (outside the function) is an
rvalue.

elision.cpp

LR

unread,
Jul 7, 2008, 8:21:25 AM7/7/08
to

> ------------------------------------------------------------------------
--------------------------------------------------------------------------
Your original code follows. Somehow it's not getting quoted in the
reply. So I put it in by hand.


{ Our apologies. Somehow an article with attachments (even if only pure text)
slipped through both moderation and our posting software. -mod/aps }

>#include <utility>
> #include <iostream>

> struct trace
> {
> trace() { std::cout << "default ctor\n"; }
> trace( trace const& ) { std::cout << "copy ctor\n"; }


> trace& operator=( trace const& ) {
std::cout << "copy assign\n"; return *this; }

How is that implemented? Perhaps
trace &operator-(const trace &t) {
std::cout << "assign" << std::endl;
trace temp(t); // one copy ctor
swap(temp); // void trace::swap(trace &); not shown
return *this;
}

> ~trace() { std::cout << "dtor\n"; }
> friend void swap( trace& x, trace& y ) { std::cout << "swap\n"; }
> };
>
> template <class T>
> struct holder
> {
> void set_by_value(T x)
> {
> using std::swap;
> swap(x, held);
> }
>


> void set_by_reference(T const& x)
> {
> T tmp(x);
> using std::swap;
> swap(tmp, held);
> }
>
> private:
> T held;
> };
>
> int main()
> {
> holder<trace> h;
>
> std::cout << "=== by reference ===\n";
> h.set_by_reference( trace() );
> std::cout << "=== by value ===\n";
> h.set_by_value( trace() );
> std::cout << "=== done ===\n";
> }
>
>------------------------------------------------------------------------
> --------------------------------------------------------------------------

After I run this code with the changes I described, and a few other
minor ones, I get this output:

default ctor
=== by reference ===
default ctor

assign
copy ctor
trace::swap(trace &t)


dtor
dtor
=== by value ===
default ctor

copy ctor
assign
copy ctor
trace::swap(trace &t)
dtor
assign
copy ctor
trace::swap(trace &t)
dtor
dtor


dtor
=== done ===
dtor


Here is the code as I modified it:

#include <utility>
#include <iostream>
#include <string>

void m(const std::string &s) {
std::cout << s << std::endl;
}

struct trace
{
void swap(trace &t) {
m("trace::swap(trace &t)");
}
trace() {m("default ctor"); }
trace(const trace &) { m("copy ctor"); }
trace& operator=(const trace &t) {
m("assign");
trace temp(t);
swap(temp);
return *this;
}
~trace() { m("dtor"); }
};

template <class T>
struct holder
{
void set_by_value(T x)
{
std::swap(x, held);
}

void set_by_reference(const T &x)
{
held = x;
}

private:
T held;
};

void f()
{
holder<trace> h;

m("=== by reference ===");
h.set_by_reference( trace() );
m("=== by value ===");
h.set_by_value( trace() );
m("=== done ===");
}

int main() {
f();

}


Your compiler seems to be doing some nice optimizations for the value
version.

The output from your by value version is,

> === by value ===
> default ctor
> swap
> dtor
> === done ===

I'm a little curious as to what's happening to the instance of trace()
that you're passing to set_by_value.

I wonder what would happen if the code was a little different, maybe,

m("=== by value ===");
const trace t;
h.set_by_value( t );
// do something else with t here
m("=== done ===");

LR

Jorgen Grahn

unread,
Jul 7, 2008, 7:36:35 PM7/7/08
to
On Wed, 2 Jul 2008 11:58:01 CST, Martin T. <0xCDC...@gmx.at> wrote:
> Hi all.
>
> When writing new C++ code, what is the point of passing any (input)
> parameter by value when passing by const reference will just work as
> well? (Even and especially PODs, I would not do it with a complex type
> anyway.)
...

> void f_ref_int(const int& x) {
> int y = x;
> y++;
> }

The number one reason against pass-by-const-reference here is not
technical: it looks funny, it is (I think it's safe to say) at best
pointless, and nobody else is doing it.

The way I react when I read someone's code and it contains odd
constructs which don't actually /do/ anything, is that I start to
distrust the rest of the code, too. Clearly, that hurts both me and
the author.

Sometimes, sticking to tradition is the best way.

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.se> R'lyeh wgah'nagl fhtagn!

David Abrahams

unread,
Jul 7, 2008, 7:57:14 PM7/7/08
to

on Mon Jul 07 2008, LR <lruss-AT-superlink.net> wrote:

> David Abrahams wrote:
> Your original code follows. Somehow it's not getting quoted in the
> reply. So I put it in by hand.
>
>
> { Our apologies. Somehow an article with attachments (even if only pure text)
> slipped through both moderation and our posting software. -mod/aps }

Mods: are you saying that my article should have been rejected because
of the inline text attachments? I'm not sure that's a great policy,
since inline plaintext is the only way to get some newsreaders not to
wrap lines, which tends to obfuscate the code.

>>#include <utility>
>> #include <iostream>
>
>> struct trace
>> {
>> trace() { std::cout << "default ctor\n"; }
>> trace( trace const& ) { std::cout << "copy ctor\n"; }
>
>
>> trace& operator=( trace const& ) {
> std::cout << "copy assign\n"; return *this; }
>
> How is that implemented? Perhaps
> trace &operator-(const trace &t) {
> std::cout << "assign" << std::endl;
> trace temp(t); // one copy ctor
> swap(temp); // void trace::swap(trace &); not shown
> return *this;
> }

Not if you want it to be efficient with rvalues. Instead:

trace& operator=(trace rhs) { swap(*this,rhs); return *this; }


>
>> ~trace() { std::cout << "dtor\n"; }
>> friend void swap( trace& x, trace& y ) { std::cout << "swap\n"; }
>> };
>>

<schnipp>

What conclusions can we draw from that?

> Your compiler seems to be doing some nice optimizations for the value
> version.
>
> The output from your by value version is,
>
>> === by value ===
>> default ctor
>> swap
>> dtor
>> === done ===
>
> I'm a little curious as to what's happening to the instance of trace()
> that you're passing to set_by_value.

It's an allowed optimization called "copy elision." Most modern
compilers do it (probably yours, even). The compiler is allowed to
eliminate any copying of an rvalue passed as a by-value argument and any
copying performed when returning by value from a function. Both
optimizations are done by allocating the storage for the argument/return
value in the caller's stack area.

> I wonder what would happen if the code was a little different, maybe,
>
> m("=== by value ===");
> const trace t;
> h.set_by_value( t );
> // do something else with t here

Now the argument is an lvalue; the compiler is forced to copy it.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Le Chaud Lapin

unread,
Jul 8, 2008, 5:23:54 PM7/8/08
to
On Jul 7, 6:36 pm, Jorgen Grahn <grahn+n...@snipabacken.se> wrote:

> On Wed, 2 Jul 2008 11:58:01 CST, Martin T. <0xCDCDC...@gmx.at> wrote:
> > void f_ref_int(const int& x) {
> > int y = x;
> > y++;
> > }
>
> The number one reason against pass-by-const-reference here is not
> technical: it looks funny, it is (I think it's safe to say) at best
> pointless, and nobody else is doing it.

Would you make this statement if 'int' were replaced with 'Foo', where
Foo is a class or struct?

> The way I react when I read someone's code and it contains odd
> constructs which don't actually /do/ anything, is that I start to
> distrust the rest of the code, too. Clearly, that hurts both me and
> the author.
>
> Sometimes, sticking to tradition is the best way.

I just did a grep for such constructs in my pet project: 1726
occurences in 535 files.

What it does for me is let caller pass aggregates by computationally-
less-expensive reference with a contract that callee will be unable to
modified object being referred to. :)

How do you pass aggregates?

-Le Chaud Lapin-


--

Tony Delroy

unread,
Jul 8, 2008, 10:28:28 PM7/8/08
to
On Jul 3, 5:27 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:
> "Martin T." <0xCDCDC...@gmx.at> wrote in message
> > When writing new C++ code, what is the point of passing any (input)
> > parameter by value when passing by const reference will just work as
> > well? (Even and especially PODs, I would not do it with a complex type
> > anyway.)
> > (Given that in 90% of the code you will never want to modify the
> > parameter anyway.)
>
> 6+ Reasons I haven't thought of

One corner case for consideration:

typedef int File_Handle;

void fn(File_Handle fh); // (A) OR
void fn(const File_Handle& fh); // (B) OR
void fn(Traits<File_Handle>::Const_Param fh); // (C) ??

I would argue that (A) presents a maintenance issue - particularly if
the typedef is provided by a library header. Consider a change to a
"class File_Handler" in which copy construction and/or destruction
have unwanted side effects (e.g. badly implemented RAII), or some
large data is added (cache, buffer, ...?). The client code (A) might
keep compiling but not run as intended.

Implications of (B) are discussed elsewhere in thread, and would be my
general preference. Approach (C) is good but clumsy, verbose and
arguably confusing/obfuscating - more appropriate when useful to
ensure optimal library code, rather than for use by default in
applications.

Cheers,
Tony

Jorgen Grahn

unread,
Jul 19, 2008, 4:37:18 PM7/19/08
to
On Tue, 8 Jul 2008 20:28:28 CST, Tony Delroy <tony_i...@yahoo.co.uk> wrote:
> On Jul 3, 5:27 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:
>> "Martin T." <0xCDCDC...@gmx.at> wrote in message
>> > When writing new C++ code, what is the point of passing any (input)
>> > parameter by value when passing by const reference will just work as
>> > well? (Even and especially PODs, I would not do it with a complex type
>> > anyway.)
>> > (Given that in 90% of the code you will never want to modify the
>> > parameter anyway.)
>>
>> 6+ Reasons I haven't thought of
>
> One corner case for consideration:
>
> typedef int File_Handle;
>
> void fn(File_Handle fh); // (A) OR
> void fn(const File_Handle& fh); // (B) OR
> void fn(Traits<File_Handle>::Const_Param fh); // (C) ??
>
> I would argue that (A) presents a maintenance issue - particularly if
> the typedef is provided by a library header. Consider a change to a
> "class File_Handler" in which copy construction and/or destruction
> have unwanted side effects (e.g. badly implemented RAII), or some
> large data is added (cache, buffer, ...?). The client code (A) might
> keep compiling but not run as intended.

Good point, but unfortunate example. The word "handle" in
"File_Handle" is intended to signal to the user "see this as some kind
of pointer or reference to a File". I think most people would expect
to be able to handle it as if it was a void *, or an index into some
array not available to the programmer.

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.se> R'lyeh wgah'nagl fhtagn!

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Jorgen Grahn

unread,
Jul 19, 2008, 4:37:00 PM7/19/08
to
On Tue, 8 Jul 2008 15:23:54 CST, Le Chaud Lapin <jaibu...@gmail.com> wrote:
> On Jul 7, 6:36 pm, Jorgen Grahn <grahn+n...@snipabacken.se> wrote:
>> On Wed, 2 Jul 2008 11:58:01 CST, Martin T. <0xCDCDC...@gmx.at> wrote:
>> > void f_ref_int(const int& x) {
>> > int y = x;
>> > y++;
>> > }
>>
>> The number one reason against pass-by-const-reference here is not
>> technical: it looks funny, it is (I think it's safe to say) at best
>> pointless, and nobody else is doing it.
>
> Would you make this statement if 'int' were replaced with 'Foo', where
> Foo is a class or struct?

No. Note the "here" in "reason against pass-by-const-reference here".
It refers to "const int&" in the example code above.

The original poster stated from the start that he was talking about
types like int, bool and so on. He, you, I and probably everyone else
agree that passing e.g. a std::string by const reference is a good
thing.

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.se> R'lyeh wgah'nagl fhtagn!

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Tony Delroy

unread,
Jul 22, 2008, 5:28:24 PM7/22/08
to
On Jul 20, 5:37 am, Jorgen Grahn <grahn+n...@snipabacken.se> wrote:

> On Tue, 8 Jul 2008 20:28:28 CST, Tony Delroy <tony_in_da...@yahoo.co.uk> wrote:
> > On Jul 3, 5:27 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:
> >> "Martin T." <0xCDCDC...@gmx.at> wrote in message
> >> > When writing new C++ code, what is the point of passing any (input)
> >> > parameter by value when passing by const reference will just work as
> >> > well? (Even and especially PODs, I would not do it with a complex type
> >> > anyway.)
> >> > (Given that in 90% of the code you will never want to modify the
> >> > parameter anyway.)
>
> > typedef int File_Handle;
>
> > void fn(File_Handle fh); // (A) OR
> > void fn(const File_Handle& fh); // (B) OR
> > void fn(Traits<File_Handle>::Const_Param fh); // (C) ??
>
> > I would argue that (A) presents a maintenance issue - particularly if
> > the typedef is provided by a library header. Consider a change to a
> > "class File_Handler" in which copy construction and/or destruction
> > have unwanted side effects (e.g. badly implemented RAII), or some
> > large data is added (cache, buffer, ...?). The client code (A) might
> > keep compiling but not run as intended.
>
> Good point, but unfortunate example. The word "handle" in
> "File_Handle" is intended to signal to the user "see this as some kind
> of pointer or reference to a File". I think most people would expect
> to be able to handle it as if it was a void *, or an index into some
> array not available to the programmer.
>
> /Jorgen

Quite so, and in general real IT references to "file handles" serve
this purpose with respect to OS-managed data. Still, consider
possible layering of convenience functions over this abstraction: a
programmer might want to "enrich" these handles with a class to, for
example, open a file and store the file handle, ensure the file handle
was closed in the destructor, support OO-style operations etc.. The
merits can be argued, but experience shows such classes do often get
written, and it's not unlikely the class would be named after the
handle abstraction it wraps. You obviously understand the issues, but
for the benefit of others: the danger in this case is only some
unintended file opens and closes and temporary use of an additional O/
S file handle resource (of which there are typically limited numbers),
but in some cases (e.g. when locks are involved), worse things like
deadlocks could occur....

Tony

--

Matthias Hofmann

unread,
Jul 24, 2008, 3:58:15 PM7/24/08
to
"Jim Langston" <tazm...@rocketmail.com> schrieb im Newsbeitrag
news:WLOak.760$gz3...@newsfe04.lga...

> 2. Passing a paramater by value allows modification of the paramater as a
> local variable I.E.
>
> void Reverse( const char* CString, int length )
> {
> while ( --length )
> {
> std::cout << CString[length];
> }
> }

I know that this does not relate to the original question, but there's an
off-by-one error in your code. The first letter of the original string will
not be displayed, i.e. "Hello" turns to "olle" rather than "olleH". You
probably meant this:

void Reverse( const char* CString, int length )
{
while ( length-- )
{
std::cout << CString[length - 1];
}
}

--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers

0 new messages