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

Don't pass by reference to non-const?

6 views
Skip to first unread message

Sousuke

unread,
May 1, 2010, 5:30:43 PM5/1/10
to
I'm having doubts about the validity of the following guideline:

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Reference_Arguments#Reference_Arguments

For some reason I haven't noticed whether this is generally followed.
Is it? Or is it just something made up at Google? What do you think of
it?

Ian Collins

unread,
May 1, 2010, 5:42:50 PM5/1/10
to

I haven't seen it used and I don't like it. It appears inconsistent,
mixing reference and pointer parameters for no good reason.

--
Ian Collins

Daniel T.

unread,
May 1, 2010, 6:10:27 PM5/1/10
to
Sousuke <s0s...@gmail.com> wrote:

Stroustrup advocates this guideline as well in "The C++ Programming
Language." I don't particularly care for it myself.

My own guideline is to use pointers as arguments if the object pointed
to has to live longer than the function being called (or if the argument
is a C array.) For example, if the function is storing the object
pointed to somewhere for later use. I use const reference as an
optimization of passing by value.

Stuart Golodetz

unread,
May 1, 2010, 6:54:15 PM5/1/10
to

That style guide's just there to document guidelines that Google wants
followed when you work with them -- the example you mention isn't the
only recommendation they make that is open to debate in a more general
context (not using exceptions would be another). As long as their
guidelines work for them, that's cool. Doesn't mean that people have to,
or necessarily should, follow them when not working with Google.

I think the motivation Google have for that specific recommendation is
to try and avoid bugs when there are lots of people working on the code
and they're not all as clued up as Google might perhaps wish. In other
words, it's a pragmatic decision based on their knowledge of/assumptions
about the programmers involved. Personally I don't think it's a
particularly great general-purpose guideline, but it's possible that
it's useful in context.

Regards,
Stu

Sousuke

unread,
May 1, 2010, 7:05:29 PM5/1/10
to
On May 1, 5:10 pm, "Daniel T." <danie...@earthlink.net> wrote:
> Sousuke <s0s...@gmail.com> wrote:
> > I'm having doubts about the validity of the following guideline:
>
> >http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showon...

> > ce_Arguments#Reference_Arguments
>
> > For some reason I haven't noticed whether this is generally followed.
> > Is it? Or is it just something made up at Google? What do you think of
> > it?
>
> Stroustrup advocates this guideline as well in "The C++ Programming
> Language." I don't particularly care for it myself.

Thanks. Could you tell me the section?

> My own guideline is to use pointers as arguments if the object pointed
> to has to live longer than the function being called (or if the argument
> is a C array.) For example, if the function is storing the object
> pointed to somewhere for later use.

Or if the pointed-to type is an abstract class, I think.

Alf P. Steinbach

unread,
May 1, 2010, 7:11:41 PM5/1/10
to
* Sousuke:

Please quote the guideline you refer to.

<quote>
Reference Arguments

All parameters passed by reference must be labeled const.

Definition: In C, if a function needs to modify a variable, the parameter must
use a pointer, eg int foo(int *pval). In C++, the function can alternatively
declare a reference parameter: int foo(int &val).

Pros: Defining a parameter as reference avoids ugly code like (*pval)++.
Necessary for some applications like copy constructors. Makes it clear, unlike
with pointers, that NULL is not a possible value.

Cons: References can be confusing, as they have value syntax but pointer semantics.

Decision:

Within function parameter lists all references must be const:

void Foo(const string &in, string *out);

In fact it is a very strong convention in Google code that input arguments are
values or const references while output arguments are pointers. Input parameters
may be const pointers, but we never allow non-const reference parameters.

One case when you might want an input parameter to be a const pointer is if you
want to emphasize that the argument is not copied, so it must exist for the
lifetime of the object; it is usually best to document this in comments as well.
STL adapters such as bind2nd and mem_fun do not permit reference parameters, so
you must declare functions with pointer parameters in these cases, too.
</quote>


I.e. Google would design std::getline with pointer argument.

It sounds political.

From a non-political perspective it's pretty stupid since it requires extra
notation and requires unnecessary bug-vectors, both something you would
absolutely not want in the code, but presumably that "decision" made sense in
some workplace politics, something with not too disturbing consequences that
some group was very opposed to but had to accept; you're the boss, man.


Cheers,

- Alf (telepathic circuit engaged)

Ian Collins

unread,
May 1, 2010, 7:19:23 PM5/1/10
to

Um, surely any object that gets passed by non-const reference lives
longer the the function being called?

--
Ian Collins

Ian Collins

unread,
May 1, 2010, 7:19:55 PM5/1/10
to

Why?

--
Ian Collins

Daniel T.

unread,
May 1, 2010, 7:33:03 PM5/1/10
to

I mean that if the function is going to assign the object to some
pointer that outlives the object. If one of my functions accepts an
argument by reference, it means the function doesn't care what you do
with the object passed in after the function returns, if it requires a
pointer, then there are specific lifetime requirements.

Daniel T.

unread,
May 1, 2010, 7:48:13 PM5/1/10
to
Sousuke <s0s...@gmail.com> wrote:
> On May 1, 5:10�pm, "Daniel T." <danie...@earthlink.net> wrote:
> > Sousuke <s0s...@gmail.com> wrote:
> > > I'm having doubts about the validity of the following guideline:
> >
> > >http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showon...
> > > ce_Arguments#Reference_Arguments
> >
> > > For some reason I haven't noticed whether this is generally followed.
> > > Is it? Or is it just something made up at Google? What do you think of
> > > it?
> >
> > Stroustrup advocates this guideline as well in "The C++ Programming
> > Language." I don't particularly care for it myself.
>
> Thanks. Could you tell me the section?

Section 7.9 Advice:

[1] Be suspicious of non-const reference arguments; if you want the
function to modify its arguments, use pointers and value return instead;
�5.5.

> > My own guideline is to use pointers as arguments if the object pointed
> > to has to live longer than the function being called (or if the argument
> > is a C array.) For example, if the function is storing the object
> > pointed to somewhere for later use.
>
> Or if the pointed-to type is an abstract class, I think.

No, even here I will use a reference unless the function imposes some
sort of lifetime restrictions on the passed in object.

Sousuke

unread,
May 1, 2010, 8:10:03 PM5/1/10
to

Maybe I'm just confused because the code I'm currently working on
deals heavily with reference-counted pointers to abstract classes (so
they're always dynamically allocated), so it makes sense to pass them
around as pointers.

Balog Pal

unread,
May 2, 2010, 5:08:36 AM5/2/10
to

"Sousuke" <s0s...@gmail.com>

As a general point, stay away from google's style guide. It has many
questionable or outright WTF points. (At least it did a year ago, when I
twitlisted it.)

Sure you can find a set of really good guides. When in doubt look at
Sutter/Alexandrescu book and its references.

James Kanze

unread,
May 2, 2010, 5:45:51 AM5/2/10
to
On May 1, 10:42 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> On 05/ 2/10 09:30 AM, Sousuke wrote:

> > I'm having doubts about the validity of the following guideline:

> >http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showon...

> > For some reason I haven't noticed whether this is generally
> > followed. Is it? Or is it just something made up at Google?
> > What do you think of it?

> I haven't seen it used and I don't like it. It appears
> inconsistent, mixing reference and pointer parameters for no
> good reason.

Yes and no. The logic is that in arguments are references, out
and inout pointers. This has two advantages:

-- It requires explicit action at the call site in order to
pass an out argument; you can see immediately that the
argument might change.

-- It ensures that even if you currently compile with a
compiler that doesn't enforce the rule forbidding
initializing a non-const reference with an rvalue (VC++, for
example), your code will compile with more "correct"
compilers: all compilers require an lvalue in order to use
the (built-in) & operator.

Neither are "killer" arguments, and certainly a lot of other
conventions are possible. In the end, you only have two
choices, and there are far more than one binary information that
might be useful to indicate. Still, way, way back, this was the
convention I preferred. I'd gotten out of it, because the
places I'd worked in used other conventions, but the circle has
turned, and where I work now uses it (and used it before I got
there).

--
James Kanze

James Kanze

unread,
May 2, 2010, 5:50:52 AM5/2/10
to
On May 1, 11:10 pm, "Daniel T." <danie...@earthlink.net> wrote:
> Sousuke <s0s...@gmail.com> wrote:
> > I'm having doubts about the validity of the following guideline:

> >http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showon...
> > ce_Arguments#Reference_Arguments

> > For some reason I haven't noticed whether this is generally
> > followed. Is it? Or is it just something made up at Google?
> > What do you think of it?

> Stroustrup advocates this guideline as well in "The C++
> Programming Language." I don't particularly care for it
> myself.

> My own guideline is to use pointers as arguments if the object
> pointed to has to live longer than the function being called
> (or if the argument is a C array.) For example, if the
> function is storing the object pointed to somewhere for later
> use.

That's another convention. Probably the most common. (At
least, it seemed to be when I did a small survey of the issue.
About 15 years ago.) A third is to use a pointer if a null
pointer is conceivably valid, a reference otherwise.

> I use const reference as an optimization of passing by
> value.

The issue here isn't const reference as an optimization of pass
by value. It's non-const referenced vs. non-const pointer for
out (and inout) parameters.

Note that regardless of the convention otherwise: if the <op>=
(and prefixed ++ and --) operators aren't members, then their
first (only) argument must be a non-const reference. (And
although I generally make them members, there are also good
arguments for a convention which makes them free functions.)

--
James Kanze

James Kanze

unread,
May 2, 2010, 6:01:18 AM5/2/10
to
On May 2, 12:11 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * Sousuke:

[...]


> I.e. Google would design std::getline with pointer argument.

> It sounds political.

Obviously. When there are several different, mutually exclusive
possibilities, all of which have valid technical arguments in
their favor, the final choice will be political. Any choice
concerning when to use references and when to use pointers in a
function interface is at least partially political.

> From a non-political perspective it's pretty stupid since it
> requires extra notation and requires unnecessary bug-vectors,

The "extra" notation is redundancy. Redundancy which makes the
code more readable and more easily understandable. (The
alternatives have other advantages, so in the end, which one you
choose is a "political" decision. None of the usual choices is
perfect, and none provides all of the possible advantages.)

And what do you mean by "bug-vectors"? I'm not familiar with
the term.

--
James Kanze

Leigh Johnston

unread,
May 2, 2010, 6:10:47 AM5/2/10
to

"Sousuke" <s0s...@gmail.com> wrote in message
news:64b3604a-c831-40f6...@r34g2000yqj.googlegroups.com...

A style guide is just that, a style guide, feel free to ignore it (who says
what Google advocates is better than what someone else advocates?) I use
pointer parameters if the function takes ownership of the pointed to object
or if I need pointer semantics (i.e. pointer arithmetic). Reference in
parameters should always be const so making out parameters non-const
references follows naturally. I disagree that forcing the user to take the
address of an object to be changed at the call site is particularly
beneficial, it is simply a form of documentation and the presence or absence
of a const qualifier is also an equally good form of documentation (albeit
not at the call site).

/Leigh

Alf P. Steinbach

unread,
May 2, 2010, 6:20:15 AM5/2/10
to
On 02.05.2010 12:01, * James Kanze:

E.g. a disease vector is a way the disease can enter your body or a population.

A bug vector is a way a bug can enter a program.

Such as inadvertently passing null-pointers to routines that don't expect them,
when that is made easy to do by the routine signature.


Cheers,

- Alf

Ian Collins

unread,
May 2, 2010, 6:41:40 AM5/2/10
to
On 05/ 2/10 09:45 PM, James Kanze wrote:
> On May 1, 10:42 pm, Ian Collins<ian-n...@hotmail.com> wrote:
>> On 05/ 2/10 09:30 AM, Sousuke wrote:
>
>>> I'm having doubts about the validity of the following guideline:
>
>>> http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showon...
>
>>> For some reason I haven't noticed whether this is generally
>>> followed. Is it? Or is it just something made up at Google?
>>> What do you think of it?
>
>> I haven't seen it used and I don't like it. It appears
>> inconsistent, mixing reference and pointer parameters for no
>> good reason.
>
> Yes and no. The logic is that in arguments are references, out
> and inout pointers. This has two advantages:
>
> -- It requires explicit action at the call site in order to
> pass an out argument; you can see immediately that the
> argument might change.
>
> -- It ensures that even if you currently compile with a
> compiler that doesn't enforce the rule forbidding
> initializing a non-const reference with an rvalue (VC++, for
> example), your code will compile with more "correct"
> compilers: all compilers require an lvalue in order to use
> the (built-in)& operator.

>
> Neither are "killer" arguments, and certainly a lot of other
> conventions are possible. In the end, you only have two
> choices, and there are far more than one binary information that
> might be useful to indicate. Still, way, way back, this was the
> convention I preferred. I'd gotten out of it, because the
> places I'd worked in used other conventions, but the circle has
> turned, and where I work now uses it (and used it before I got
> there).

I guess those are sound arguments. But I find I seldom use out
parameters. I something has to be returned, return it!

--
Ian Collins

Balog Pal

unread,
May 2, 2010, 8:00:57 AM5/2/10
to

"Ian Collins" <ian-...@hotmail.com>

>> Yes and no. The logic is that in arguments are references, out
>> and inout pointers. This has two advantages:
>>
>> -- It requires explicit action at the call site in order to
>> pass an out argument; you can see immediately that the
>> argument might change.
>>
>> -- It ensures that even if you currently compile with a
>> compiler that doesn't enforce the rule forbidding
>> initializing a non-const reference with an rvalue (VC++, for
>> example), your code will compile with more "correct"
>> compilers: all compilers require an lvalue in order to use
>> the (built-in)& operator.
>>
>> Neither are "killer" arguments, and certainly a lot of other
>> conventions are possible. In the end, you only have two
>> choices, and there are far more than one binary information that
>> might be useful to indicate. Still, way, way back, this was the
>> convention I preferred. I'd gotten out of it, because the
>> places I'd worked in used other conventions, but the circle has
>> turned, and where I work now uses it (and used it before I got
>> there).
>
> I guess those are sound arguments. But I find I seldom use out
> parameters. I something has to be returned, return it!

Also they goe against the naturals. Reference means there is always an
object. Pointer can be NULL so that implies an optional thing.

Then again, the very lack of const in the signature documents that it is an
out parameter. With poiter or reference all the same.

In C++ code I try to limit pointer usage to bare minimum. Watering that up
is not good.

OTOH, I agree with the latter observation. In the early times I used to pass
an empty object frequently to 'fill' in a function instead of returning it.
retutning vectors of stuff looked bad. But I left it behind eventually. So
out params are indeed rare in my code, possibly limited to cases when I have
multiple items that are chosen not to be tupled. That still leaves the
input params for nonconst refs.

Daniel T.

unread,
May 2, 2010, 10:17:09 AM5/2/10
to
James Kanze <james...@gmail.com> wrote:
>
> Note that regardless of the convention otherwise: if the <op>= (and
> prefixed ++ and --) operators aren't members, then their first (only)
> argument must be a non-const reference. (And although I generally
> make them members, there are also good arguments for a convention
> which makes them free functions.)

When op<< is a free function, the first argument is a non-const
reference. I guess Google is saying that op<< cannot be defined for any
user type, or are they demanding that the calling code must look like
&cout << myObject;

Stuart Golodetz

unread,
May 2, 2010, 10:59:00 AM5/2/10
to

Well another of their guidelines is:

"Do not overload operators except in rare, special circumstances."

So I suspect the issue doesn't arise for them too often.

Stu

Andy Champ

unread,
May 2, 2010, 12:09:21 PM5/2/10
to
James Kanze wrote:
>
> That's another convention.

<snip>


> A third is to use a pointer if a null
> pointer is conceivably valid, a reference otherwise.
>

That's what we do. And we insist that you explicitly check for pointer
validity.

Andy

James Kanze

unread,
May 2, 2010, 6:14:05 PM5/2/10
to
vOn May 2, 11:41 am, Ian Collins <ian-n...@hotmail.com> wrote:
> On 05/ 2/10 09:45 PM, James Kanze wrote:

[...]


> I guess those are sound arguments. But I find I seldom use out
> parameters. I something has to be returned, return it!

In general, I agree, and out parameters should be fairly rare.
There are some exceptions, however: anyone who's written a large
application in Java will certainly be aware of them (since Java
has no support for out parameters what so ever). And sometimes,
performance issues raise their ugly head---in my current work,
we do use out parameters of things like std::vector<double>,
because returning a vector with a couple of thousand elements
was too slow.

--
James Kanze

James Kanze

unread,
May 2, 2010, 6:18:41 PM5/2/10
to
On May 2, 3:17 pm, "Daniel T." <danie...@earthlink.net> wrote:
> James Kanze <james.ka...@gmail.com> wrote:

Yes. Operator overloading is a special case. They don't seem
to make an explicit exception, but presumably, it would be
allowed. (Operator overloading is widely abused, and should be
limited much more than it normally is. But the << is an
established use. And for things like +=, as I said, there are
some very good arguments for making it a non-member. Even if I
don't do so.)

--
James Kanze

James Kanze

unread,
May 2, 2010, 6:23:05 PM5/2/10
to
On May 2, 3:59 pm, Stuart Golodetz

<sgolod...@NdOiSaPlA.pMiPpLeExA.ScEom> wrote:
> Daniel T. wrote:

That's a good rule in general, but there are some obvious
exceptions: any class with value semantics should overload
operator=, for example, and any class which models a numeric
value should probably overload the appropriate mathematical
operators. Throw in operator* and operator-> for smart
pointers, and operator[] for "arrays", and IMHO, that about
covers it. (The use of ++ to advance an iterator is debatable.)

--
James Kanze

James Kanze

unread,
May 2, 2010, 6:26:22 PM5/2/10
to
On May 2, 11:20 am, "Alf P. Steinbach" <al...@start.no> wrote:
> On 02.05.2010 12:01, * James Kanze:

[..]


> > And what do you mean by "bug-vectors"? I'm not familiar with
> > the term.

> E.g. a disease vector is a way the disease can enter your body
> or a population.

> A bug vector is a way a bug can enter a program.

OK. For some reason, I interpreted "vector" in its C++ meaning.

> Such as inadvertently passing null-pointers to routines that
> don't expect them, when that is made easy to do by the routine
> signature.

Yes. That's an argument for a different convention. As I said,
there are valid arguments for several different conventions.

--
James Kanze

Balog Pal

unread,
May 2, 2010, 6:42:49 PM5/2/10
to

"James Kanze" <james...@gmail.com>

> And sometimes,
> performance issues raise their ugly head---in my current work,
> we do use out parameters of things like std::vector<double>,
> because returning a vector with a couple of thousand elements
> was too slow.

You mean you had a situation wanting performance yet you used a compiler
that did so poor job on optimization that retutning a vector was actually
slower than passing in an empty one by reference?

Ian Collins

unread,
May 2, 2010, 9:11:42 PM5/2/10
to

I was about to post the same comment (until some prawn in a digger hit
our power cable!). I ran a quick test and found passing by reference
slower than returning a vector of 10000 doubles. I had expected them to
be about the same.

--
Ian Collins

Alf P. Steinbach

unread,
May 2, 2010, 11:43:34 PM5/2/10
to
On 03.05.2010 03:11, * Ian Collins:

When you do it manually instead of RVO you have an extra default construct
construction and an extra swap, but it shouldn't really matter for efficiency.

What results did you obtain?

Doing it manually is more fragile, though.


Cheers,

- Alf

Alf P. Steinbach

unread,
May 2, 2010, 11:54:55 PM5/2/10
to
On 02.05.2010 11:45, * James Kanze:

> On May 1, 10:42 pm, Ian Collins<ian-n...@hotmail.com> wrote:
>> On 05/ 2/10 09:30 AM, Sousuke wrote:
>
>>> I'm having doubts about the validity of the following guideline:
>
>>> http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showon...
>
>>> For some reason I haven't noticed whether this is generally
>>> followed. Is it? Or is it just something made up at Google?
>>> What do you think of it?
>
>> I haven't seen it used and I don't like it. It appears
>> inconsistent, mixing reference and pointer parameters for no
>> good reason.
>
> Yes and no. The logic is that in arguments are references, out
> and inout pointers. This has two advantages:
>
> -- It requires explicit action at the call site in order to
> pass an out argument; you can see immediately that the
> argument might change.

Sorry, no, you can't in general.

It's just an urban myth.

For example,

foo( v );

Here v might be a pointer denoting an out argument. Or v might be an object with
pointers to other objects. Concluding that foo can't change anything because
there's no address operator in the call is just stupid; one has to know about
foo, and for that matter, about v.


> -- It ensures that even if you currently compile with a
> compiler that doesn't enforce the rule forbidding
> initializing a non-const reference with an rvalue (VC++, for
> example), your code will compile with more "correct"
> compilers: all compilers require an lvalue in order to use
> the (built-in)& operator.

As I recall VC warns about that, so, no problem, argument moot.


> Neither are "killer" arguments

They're certainly not "killer" arguments: they're void arguments. :-)


>, and certainly a lot of other
> conventions are possible. In the end, you only have two
> choices, and there are far more than one binary information that
> might be useful to indicate. Still, way, way back, this was the
> convention I preferred.

Well, I've also used silly in-practice-detrimental conventions, like

void foo()
{
bar();
}

But one would sort of expect a modern firm like Google to not /require/ its
developers to do such silly things, and to have understood the problems of
micro-management and simply not do that.

Hence my conclusion that it's most likely political.


> I'd gotten out of it, because the
> places I'd worked in used other conventions, but the circle has
> turned, and where I work now uses it (and used it before I got
> there).

The state of knowledge & understanding advances /very/ slowly.


Cheers,

- Alf

Stuart Golodetz

unread,
May 3, 2010, 6:41:47 AM5/3/10
to

What are the arguments for making things like operator+= a non-member,
out of interest? I'm aware of an (the?) argument for things like
operator+, where you often want to allow conversions on the left-hand
argument as well as the right, but what's the argument for the '='
versions please?

Regards,
Stu

> --
> James Kanze

Kai-Uwe Bux

unread,
May 3, 2010, 8:02:34 AM5/3/10
to
Stuart Golodetz wrote:

> James Kanze wrote:
>> (
[...]


>> And for things like +=, as I said, there are
>> some very good arguments for making it a non-member. Even if I
>> don't do so.)
>
> What are the arguments for making things like operator+= a non-member,
> out of interest? I'm aware of an (the?) argument for things like
> operator+, where you often want to allow conversions on the left-hand
> argument as well as the right, but what's the argument for the '='
> versions please?

If you make it a non-member, operator+= behaves more like the version for
built-in types: you cannot call it on a temporary. As a member function, you
could:

*( begin() += 5 )
*( ++ begin() )

Whether that is an advantage or a shortcoming depends on your point of view.
However, for implementations of the standard library iterators, I would
choose the non-member approach since ++begin() is not guaranteed to compile
by the standard and I would love to see the implementation catch that non-
portable use.


Best

Kai-Uwe Bux

Keith H Duggar

unread,
May 3, 2010, 8:41:14 AM5/3/10
to
On May 3, 6:41 am, Stuart Golodetz

For some reasons read:

http://www.drdobbs.com/cpp/184401197

Most of the arguments apply to both operator and non-operator
functions.

KHD

Stuart Golodetz

unread,
May 3, 2010, 9:36:12 AM5/3/10
to

Ah, that makes sense. Thanks!

Stu

Stuart Golodetz

unread,
May 3, 2010, 9:36:38 AM5/3/10
to

Cheers for the link -- will take a look :)

Stu

James Kanze

unread,
May 4, 2010, 5:36:05 AM5/4/10
to
On 3 May, 04:43, "Alf P. Steinbach" <al...@start.no> wrote:
> On 03.05.2010 03:11, * Ian Collins:
> > On 05/ 3/10 10:42 AM, Balog Pal wrote:

> >> "James Kanze" <james.ka...@gmail.com>

> >>> And sometimes, performance issues raise their ugly
> >>> head---in my current work, we do use out parameters of
> >>> things like std::vector<double>, because returning
> >>> a vector with a couple of thousand elements was too slow.

> >> You mean you had a situation wanting performance yet you
> >> used a compiler that did so poor job on optimization that
> >> retutning a vector was actually slower than passing in an
> >> empty one by reference?

I love it when people comment about things they know nothing
about. We did the measures with a number of different
compilers: VC++, g++, Intel and Sun CC. In all cases, passing
the pre-constructed vector to the function was significantly
faster than returning a vector.

> > I was about to post the same comment (until some prawn in
> > a digger hit our power cable!). I ran a quick test and found
> > passing by reference slower than returning a vector of 10000
> > doubles. I had expected them to be about the same.

> When you do it manually instead of RVO you have an extra
> default construct construction and an extra swap, but it
> shouldn't really matter for efficiency.

The compiler can't always use RVO. Our two versions were:

std::vector<double> v(...);
for (... lot's of iterations ... )
{
// calculate some values based on the current contents
// of v.
v = some_function(... the calculated values ...);
// ...
}

as opposed to

std::vector<double> v(...);
for (... lot's of iterations ... )
{
// calculate some values based on the current contents
// of v.
some_function(&v, ... the calculated values ...);
// ...
}

(As far as I can tell, this is a more or less standard procedure
in numerical analysis. Although in some cases, you might have
two vectors, one with the old values, and one in which you put
the new, swapping them each time you go through the loop.)

--
James Kanze

James Kanze

unread,
May 4, 2010, 5:45:43 AM5/4/10
to
On 3 May, 04:54, "Alf P. Steinbach" <al...@start.no> wrote:
> On 02.05.2010 11:45, * James Kanze:

[...]


> > Yes and no. The logic is that in arguments are references, out
> > and inout pointers. This has two advantages:

> > -- It requires explicit action at the call site in order to
> > pass an out argument; you can see immediately that the
> > argument might change.

> Sorry, no, you can't in general.

> It's just an urban myth.

> For example,

> foo( v );

> Here v might be a pointer denoting an out argument.

The caller of foo has v handy. He knows it's a pointer.

> Or v might be an object with pointers to other objects.
> Concluding that foo can't change anything because there's no
> address operator in the call is just stupid; one has to know
> about foo, and for that matter, about v.

Sure, you can do all sorts of stupid things, regardless of the
convention used.

In actual practice, this particular convention reduces
errors. Measurably. So do some of the other conventions
suggested. So you have to choose according to which one seems
most important in your context.

> > -- It ensures that even if you currently compile with a
> > compiler that doesn't enforce the rule forbidding
> > initializing a non-const reference with an rvalue (VC++, for
> > example), your code will compile with more "correct"
> > compilers: all compilers require an lvalue in order to use
> > the (built-in)& operator.

> As I recall VC warns about that, so, no problem, argument moot.

As I recall, it doesn't, but it possibly (probably) depends on
the version.

> > Neither are "killer" arguments

> They're certainly not "killer" arguments: they're void
> arguments. :-)

Except in actual practice.

> >, and certainly a lot of other
> > conventions are possible. In the end, you only have two
> > choices, and there are far more than one binary information that
> > might be useful to indicate. Still, way, way back, this was the
> > convention I preferred.

> Well, I've also used silly in-practice-detrimental conventions, like
>
> void foo()
> {
> bar();
> }

> But one would sort of expect a modern firm like Google to not
> /require/ its developers to do such silly things, and to have
> understood the problems of micro-management and simply not do
> that.

> Hence my conclusion that it's most likely political.

No one disputes your "conclusion", since any choice between two
or more alternatives is in some way "political".

--
James Kanze

Alf P. Steinbach

unread,
May 4, 2010, 9:15:26 AM5/4/10
to
On 04.05.2010 11:45, * James Kanze:

> On 3 May, 04:54, "Alf P. Steinbach"<al...@start.no> wrote:
>> On 02.05.2010 11:45, * James Kanze:
>
> [...]
>>> Yes and no. The logic is that in arguments are references, out
>>> and inout pointers. This has two advantages:
>
>>> -- It requires explicit action at the call site in order to
>>> pass an out argument; you can see immediately that the
>>> argument might change.
>
>> Sorry, no, you can't in general.
>
>> It's just an urban myth.
>
>> For example,
>
>> foo( v );
>
>> Here v might be a pointer denoting an out argument.
>
> The caller of foo has v handy. He knows it's a pointer.

I think you mean "the one who writes the code calling foo", otherwise it doesn't
make sense.

But the alleged advantage is not for that person writing the code, who would
know it was an out-param anyway.

The alleged advantage iss about someone else reading the code, who allegedly
could see from the call's lack of address operator that it's an out-param. And
clearly he/she can't. Hence the argument is void.


>> Or v might be an object with pointers to other objects.
>> Concluding that foo can't change anything because there's no
>> address operator in the call is just stupid; one has to know
>> about foo, and for that matter, about v.
>
> Sure, you can do all sorts of stupid things, regardless of the
> convention used.

Yes, but that is not relevant.


> In actual practice, this particular convention reduces
> errors. Measurably. So do some of the other conventions
> suggested. So you have to choose according to which one seems
> most important in your context.
>
>>> -- It ensures that even if you currently compile with a
>>> compiler that doesn't enforce the rule forbidding
>>> initializing a non-const reference with an rvalue (VC++, for
>>> example), your code will compile with more "correct"
>>> compilers: all compilers require an lvalue in order to use
>>> the (built-in)& operator.
>
>> As I recall VC warns about that, so, no problem, argument moot.
>
> As I recall, it doesn't, but it possibly (probably) depends on
> the version.

<example>
C:\test> cl /W4 x.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

x.cpp
x.cpp(5) : warning C4239: nonstandard extension used : 'argument' : conversion
from 'T' to 'T &'
A non-const reference may only be bound to an lvalue
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

/out:x.exe
x.obj

C:\test>
</example>

Some do maintain that upping the warning the level is impractictal due to
Microsoft's own dirty code. However, most Windows headers (in particular the
full [windows.h]) compile without warnings at level 4, when the appropriate few
silly-warnings have been turned off. Which one should do as a matter of course.


>>> Neither are "killer" arguments
>
>> They're certainly not "killer" arguments: they're void
>> arguments. :-)
>
> Except in actual practice.

You're saying "except in some circumstances that I refuse to discuss". Oh well.


>>> , and certainly a lot of other
>>> conventions are possible. In the end, you only have two
>>> choices, and there are far more than one binary information that
>>> might be useful to indicate. Still, way, way back, this was the
>>> convention I preferred.
>
>> Well, I've also used silly in-practice-detrimental conventions, like
>>
>> void foo()
>> {
>> bar();
>> }
>
>> But one would sort of expect a modern firm like Google to not
>> /require/ its developers to do such silly things, and to have
>> understood the problems of micro-management and simply not do
>> that.
>
>> Hence my conclusion that it's most likely political.
>
> No one disputes your "conclusion", since any choice between two
> or more alternatives is in some way "political".


Cheers,

- Alf

Yannick Tremblay

unread,
May 6, 2010, 6:48:02 AM5/6/10
to
In article <hrjf60$1e64$1...@news.ett.com.ua>, Balog Pal <pa...@lib.hu> wrote:
>
>"Sousuke" <s0s...@gmail.com>

>> I'm having doubts about the validity of the following guideline:
>>
>> http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Reference_Arguments#Reference_Arguments

>>
>> For some reason I haven't noticed whether this is generally followed.
>> Is it? Or is it just something made up at Google? What do you think of
>> it?
>
>As a general point, stay away from google's style guide. It has many
>questionable or outright WTF points. (At least it did a year ago, when I
>twitlisted it.)
>
>Sure you can find a set of really good guides. When in doubt look at
>Sutter/Alexandrescu book and its references.
>

I would strongly second that. Google so-called C++ style guide
contains a lot of stuff that is very questionable. Certainly not
conductive to quality modern C++ development by skilled C++
developpers.

Taken individually, each of these guidelines are somewhat justifiable
but the sum is not something I would recommend unless you have to work
within the constraints and assumptions that google has used to come up
with these guidelines (which probably include political considerations,
legacy code considerations, skill level considerations, etc.)

Sutter and Alexandrescu book is a much superior starting point.


Yannick

Balog Pal

unread,
May 8, 2010, 11:43:23 AM5/8/10
to
"James Kanze" <james...@gmail.com>

> I love it when people comment about things they know nothing
> about.

... or fail to read minds auto-correcting misleading forum comments?

> The compiler can't always use RVO. Our two versions were:
>
> std::vector<double> v(...);
> for (... lot's of iterations ... )
> {
> // calculate some values based on the current contents
> // of v.
> v = some_function(... the calculated values ...);
> // ...
> }
>
> as opposed to
>
> std::vector<double> v(...);
> for (... lot's of iterations ... )
> {
> // calculate some values based on the current contents
> // of v.
> some_function(&v, ... the calculated values ...);
> // ...
> }

In this example you clearly use the vector as INOUT parameter, and have a
performance gain from that fact. Originally we were talking about OUT
parameters...

James Kanze

unread,
May 8, 2010, 7:27:13 PM5/8/10
to
On May 8, 4:43 pm, "Balog Pal" <p...@lib.hu> wrote:
> "James Kanze" <james.ka...@gmail.com>

> > as opposed to

In this example (in the actual code), the vector is a pure
output parameter.

> Originally we were talking about OUT parameters...

So was I.

--
James Kanze

Thomas J. Gritzan

unread,
May 8, 2010, 7:39:01 PM5/8/10
to
Am 08.05.2010 17:43, schrieb Balog Pal:
> "James Kanze" <james...@gmail.com>
>
>> I love it when people comment about things they know nothing
>> about.
>
> .... or fail to read minds auto-correcting misleading forum comments?

>
>> The compiler can't always use RVO. Our two versions were:
>>
>> std::vector<double> v(...);
>> for (... lot's of iterations ... )
>> {
>> // calculate some values based on the current contents
>> // of v.
>> v = some_function(... the calculated values ...);
>> // ...
>> }
>>
>> as opposed to
>>
>> std::vector<double> v(...);
>> for (... lot's of iterations ... )
>> {
>> // calculate some values based on the current contents
>> // of v.
>> some_function(&v, ... the calculated values ...);
>> // ...
>> }
>
> In this example you clearly use the vector as INOUT parameter, and have
> a performance gain from that fact. Originally we were talking about OUT
> parameters...

No. The performance gain comes from the fact that he only allocates
memory once and uses this memory for all iterations.
It's the same with std::getline (in a loop), where the output string's
capacity grows to the maximal line length at some time, and then there's
no more allocation unless you copy the strings.

--
Thomas

Ian Collins

unread,
May 8, 2010, 7:59:26 PM5/8/10
to

That is true, but it's interesting how close the two approaches are in
performance when that factor is removed. Comparing case 1:

std::vector<std::vector<double> > v(loops);
for( int n = 0; n < loops; ++n )
{
fn1(v[n]);
double d = v[n][4999];
}

with case 2:

std::vector<std::vector<double> > v(loops);
for( int n = 0; n < loops; ++n )
{
v[n] = fn2();
double d = v[n][4999];
}

Where f1 and f2 are:

void fn1( std::vector<double>& v ) {
for( int i = 0; i < 1000000; ++i ) v.push_back( 42.0*i );
}

std::vector<double> fn2() {
std::vector<double> v;
for( int i = 0; i < 1000000; ++i ) v.push_back( 42.0*i );
return v;
}

I see 3.73 seconds for case 1 and 4.07 seconds for case 2.

--
Ian Collins

James Kanze

unread,
May 9, 2010, 5:10:18 AM5/9/10
to
On May 9, 12:59 am, Ian Collins <ian-n...@hotmail.com> wrote:
> On 05/ 9/10 11:39 AM, Thomas J. Gritzan wrote:
> > Am 08.05.2010 17:43, schrieb Balog Pal:
> >> "James Kanze"<james.ka...@gmail.com>

[...]

> with case 2:

That's not quite the same thing. A closer approximation would
be something like:

std::vector<double> f1()
{
std::vector<double> retval;
for ( int i = 0; i < 1000000; ++i ) v.push_back( 42.0 * i );
return retval;
}

void f2( std::vector<double>& retval )
{
retval.clear();
for ( int i = 0; i < 1000000; ++i ) v.push_back( 42.0 * i );
}

or even:

void f2( std::vector<double>& retval )
{
assert( retval.size() >= 1000000 );
for ( int i = 0; i < 1000000; ++ ) v[i] = 42.0 * i;
}

Where f1 or f2 is called in a loop (and in the case of f2, the
definition of the vector is outside of the loop).

> std::vector<double> fn2() {
> std::vector<double> v;
> for( int i = 0; i < 1000000; ++i ) v.push_back( 42.0*i );
> return v;
> }

> I see 3.73 seconds for case 1 and 4.07 seconds for case 2.

The issue isn't as clear cut as that, even in your example. In
a real program, for example, using push_back each time on a new
vector will result in more allocations, and possibly (probably?)
more fragmentation.

Anyway, the fact is that we originally used the "natural"
version, returning the vector, that the program was too slow,
that one of the changes we tried was passing the vector as an
out parameter, and that it made a significant difference.

And that the compiler we were using did RVO (both named and
unnamed), but that the context we we working in didn't allow it.
(IIRC, the vector was part of a larger struct.)

--
James Kanze

Balog Pal

unread,
May 9, 2010, 4:44:59 PM5/9/10
to

"James Kanze" <james...@gmail.com>

>> > std::vector<double> v(...);
>> > for (... lot's of iterations ... )
>> > {
>> > // calculate some values based on the current contents
>> > // of v.
>> > some_function(&v, ... the calculated values ...);
>> > // ...
>> > }
>
>> In this example you clearly use the vector as INOUT parameter,
>> and have a performance gain from that fact.
>
> In this example (in the actual code), the vector is a pure
> output parameter.

It isn't, as you smuggle in its previous state across iterations. You even
init it to something before the first.

Can you show the content of some_function please to make the source of
performance clear?


Balog Pal

unread,
May 9, 2010, 4:49:12 PM5/9/10
to
"Thomas J. Gritzan" <phygon_...@gmx.de>

>>> std::vector<double> v(...);
>>> for (... lot's of iterations ... )
>>> {
>>> // calculate some values based on the current contents
>>> // of v.
>>> some_function(&v, ... the calculated values ...);
>>> // ...
>>> }
>>
>> In this example you clearly use the vector as INOUT parameter, and have
>> a performance gain from that fact. Originally we were talking about OUT
>> parameters...
>
> No. The performance gain comes from the fact that he only allocates
> memory once and uses this memory for all iterations.

Of course. And then what your "No" applies to? That preallocated memory is
IN param used in the called function. That is why it is not out, but inout
case.


Thomas J. Gritzan

unread,
May 10, 2010, 9:52:53 AM5/10/10
to

When passing memory counts as IN param, then every OUT parameter is also
an IN parameter, because if you wouldn't pass (pointers to) memory in,
you would have no place to store the OUT parameters.

--
Thomas

Balog Pal

unread,
May 10, 2010, 4:31:13 PM5/10/10
to

IMO that is a too simplistic and impractical view.

If the called function does like:

void foo( Vector & param)
{
Vector res;
/// ... fill res;
param.swap(res);
}

then it uses param as out only. Any state param could have will not leak
in. However,

{
param.resize(0);
param.reserve(100);
// do 100 push-backs
}
or
{
param.resize(100);
// assign to elements [0] - [99]
}

uses the state of param as it was passed in. And performance of the function
will be different in latter cases if you do just
Vector v();
or also do
v.reserve(100);
before calling foo(v);

Or like in a loop example just let it roll -- the first time allocation
happens then all the further calls keep the block.

Selling this as pure OUT parameter will not fly in my terminology.

The issue is not straightforward because the state of contained elements do
not differ in the alternatives. But capacity() is also part of the state.
With another collection, we could have similar state but entirely private,
and it still would count.

0 new messages