Connecting Tech Pros Worldwide Forums | Help | Site Map

Pointers vs References: A Question on Style

Desmond Liu
Guest
 
Posts: n/a
#1: Jul 22 '05
I've read articles like Scott Meyer's EC++ (Item 22) that advocate the use
of references when passing parameters. I understand the reasoning behind
using references--you avoid the cost of creating a local object when you
pass an object by reference.

But why use a reference? Is there any inherent advantage of using a
reference over using a pointer? My workplace discourages the use of
pointers when it comes to parameter passing. They always prefer references.

I would argue one reason why we might consider using a pointer is to help
communicate intent. For example, suppose I do the following in C:

#include "foo.h"

int main(int argc, char *argv[])
{
int x=5;

foo(x);

printf("%d\n",x);

return 0;
}

I can guarantee that the program will print '5' because C only supports
pass-by-value. If we're using C++, I can't make that guarantee because
we're allowed to pass-by-reference.

But if I use pointers in parameter-passing, I can use the address-of
operator to communicate intent to other programmers that the parameter
is meant to be modified. For example,

#include "A.h"
#include "X.h"

int main(int argc, char *argv[])
{
A a;
X x;

x.foo(&a); // the intent of this member function is to modify 'a'
// A non-const member function of 'a' will be called.

x.bar(a); // this member function will NOT modify 'a'. Only const
// member functions of 'a' will be called.

std::cout << a << std::endl;

return 0;
}

If I'm having problems with object 'a', I see that member function bar()
will not change object 'a' (by convention), and that my problem is likely
in member function foo(). This is especially useful if I'm sifting through
a large amount of code to track down a problem. By using this convention, I
can save time not having to look at every member function in the class
declaration to see which ones might be the cause of my problem.

Of course, all programmers have to adhere to the convention in order for it
to be useful. So to make a long story short, is it better to do
this:

void x::foo(A* a); // foo() will modify 'a'
void x::bar(const A& a); // bar() will not modify 'a'

Or is it better to do what my workplace requires?

void x::foo(A& a); // foo() will modify 'a'
void x::bar(const A& a); // bar() will not modify 'a'

Am I wrong in suggesting the use of pointers for parameter-passing? Is
there a reason why a reference should always be preferred over a pointer?
My thinking is that this convention would make the C++ code more readable.

----
Desmond

(Remove the 'nospam' from the address for e-mail replies, but I prefer
reply posts to the newsgroup)

JKop
Guest
 
Posts: n/a
#2: Jul 22 '05

re: Pointers vs References: A Question on Style


There are 2 and only 2 situations in which I choose a pointer over a
reference:

1) When it must be re-seated

2) When arrays are involved

[color=blue]
> I understand the reasoning behind
> using references--you avoid the cost of
> creating a local object when you
> pass an object by reference.[/color]


Incorrect. The nature of today's computers (ie. stack and registers) still
require a hidden pointer. (This is ofcourse where outline functions are
involved).


-JKop
DaKoadMunky
Guest
 
Posts: n/a
#3: Jul 22 '05

re: Pointers vs References: A Question on Style


>There are 2 and only 2 situations in which I choose a pointer over a[color=blue]
>reference:
>
>1) When it must be re-seated
>
>2) When arrays are involved[/color]

Another possibility is when a function argument is optional. Pointers can be
null whereas references cannot.
Phlip
Guest
 
Posts: n/a
#4: Jul 22 '05

re: Pointers vs References: A Question on Style


DaKoadMunky wrote:
[color=blue][color=green]
> >There are 2 and only 2 situations in which I choose a pointer over a
> >reference:
> >
> >1) When it must be re-seated
> >
> >2) When arrays are involved[/color]
>
> Another possibility is when a function argument is optional. Pointers can[/color]
be[color=blue]
> null whereas references cannot.[/color]

One good style rule is to never return null, and never accept null as
parameter.

Follow that rule by passing in instead a Null Object. Consider this code:

void funk(SimCity const * pCity)
{
if (pCity)
pCity->throwParade();
}

Now contrast with this:

class NullCity: public SimCity
{
public: /*virtual*/ void throwParade() {}
};

void funk(SimCity const & aCity)
{
aCity.throwParade();
}

The code simplifies because it pushes behavior behind an interface. The
interface simply promises to its caller that it is doing something, whether
or not it really is. Patterns like this are the heart of OO - programming to
the interface instead of the implementation.

Desmond Liu wrote:
[color=blue]
> But why use a reference? Is there any inherent advantage of using a
> reference over using a pointer? My workplace discourages the use of
> pointers when it comes to parameter passing. They always prefer[/color]
references.

You need to pair-program with your colleagues, because if they know just
enough C++ to write that advice down, they probably know much more verbally.

The C++ keyword const instructs compilers to reject overt attempts to change
a variable's value. Covert attempts produce undefined behavior, meaning
anything could happen.

C++ functions can take arguments by copy, by address, or by reference.
Ideally, if an object passed into a function does not change, the object
should pass by copy:

void foo(SimCity aCity);

That code is inefficient. In general, programmers should not stress about
efficiency until they have enough code to measure it and find the slow
spots. In this situation, a more efficient implementation is equal cost.
When we pass by reference, our program spends no time making a huge copy of
an entire city:

void foo(SimCity &aCity);

Now if foo() won't change that city's value, the function should declare
that intention in its interface, using pass-by-constant-reference to
simulate pass-by-copy:

void foo(SimCity const &aCity);

That is the most efficient call syntax, cognitively and physically. It's
cognitively efficient because it gives foo() no copied object to foolishly
change and then discard. Statements inside foo() that might attempt to
change that city shouldn't compile. It's physically efficient because the
compiler produces opcodes that only give foo() a handle to an existing city,
without copying it.

C++ supports qualifications before their qualified types, such as "const
SimCity &". I try to write expressions with the most important part first.
There are also subtle technical reasons, in rare situations, to write
"SimCity const &", with the const after its type.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces



Dave Townsend
Guest
 
Posts: n/a
#5: Jul 22 '05

re: Pointers vs References: A Question on Style


I prefer to use references over pointers when I can. One of my strong
reasons is a reference should be referencing a valid object, whereas
a pointer you should always check that it is not NULL before using
it. The code is a little bit less "noisy" since I don't have the -> or *
dererencing to look at.

In situations where an object may be passed or not, or may be present
or not, a pointer is needed.

dave

"Desmond Liu" <dliu7647nospam@shaw.ca> wrote in message
news:Xns95319D83E984dliu7647nospamshawca@64.59.144 .76...[color=blue]
> I've read articles like Scott Meyer's EC++ (Item 22) that advocate the use
> of references when passing parameters. I understand the reasoning behind
> using references--you avoid the cost of creating a local object when you
> pass an object by reference.
>
> But why use a reference? Is there any inherent advantage of using a
> reference over using a pointer? My workplace discourages the use of
> pointers when it comes to parameter passing. They always prefer[/color]
references.[color=blue]
>
> I would argue one reason why we might consider using a pointer is to help
> communicate intent. For example, suppose I do the following in C:
>
> #include "foo.h"
>
> int main(int argc, char *argv[])
> {
> int x=5;
>
> foo(x);
>
> printf("%d\n",x);
>
> return 0;
> }
>
> I can guarantee that the program will print '5' because C only supports
> pass-by-value. If we're using C++, I can't make that guarantee because
> we're allowed to pass-by-reference.
>
> But if I use pointers in parameter-passing, I can use the address-of
> operator to communicate intent to other programmers that the parameter
> is meant to be modified. For example,
>
> #include "A.h"
> #include "X.h"
>
> int main(int argc, char *argv[])
> {
> A a;
> X x;
>
> x.foo(&a); // the intent of this member function is to modify 'a'
> // A non-const member function of 'a' will be called.
>
> x.bar(a); // this member function will NOT modify 'a'. Only const
> // member functions of 'a' will be called.
>
> std::cout << a << std::endl;
>
> return 0;
> }
>
> If I'm having problems with object 'a', I see that member function bar()
> will not change object 'a' (by convention), and that my problem is likely
> in member function foo(). This is especially useful if I'm sifting through
> a large amount of code to track down a problem. By using this convention,[/color]
I[color=blue]
> can save time not having to look at every member function in the class
> declaration to see which ones might be the cause of my problem.
>
> Of course, all programmers have to adhere to the convention in order for[/color]
it[color=blue]
> to be useful. So to make a long story short, is it better to do
> this:
>
> void x::foo(A* a); // foo() will modify 'a'
> void x::bar(const A& a); // bar() will not modify 'a'
>
> Or is it better to do what my workplace requires?
>
> void x::foo(A& a); // foo() will modify 'a'
> void x::bar(const A& a); // bar() will not modify 'a'
>
> Am I wrong in suggesting the use of pointers for parameter-passing? Is
> there a reason why a reference should always be preferred over a pointer?
> My thinking is that this convention would make the C++ code more readable.
>
> ----
> Desmond
>
> (Remove the 'nospam' from the address for e-mail replies, but I prefer
> reply posts to the newsgroup)[/color]


Phlip
Guest
 
Posts: n/a
#6: Jul 22 '05

re: Pointers vs References: A Question on Style


Dave Townsend wrote:
[color=blue]
> In situations where an object may be passed or not, or may be present
> or not, a pointer is needed.[/color]

Read my post.

I think I might be able to extend the NullObject concept to say not using it
violates the Liskov Substitution Principle...

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces


Dave Townsend
Guest
 
Posts: n/a
#7: Jul 22 '05

re: Pointers vs References: A Question on Style


Agreed, but using a NullObject only relates to new classes, not
legacy ones I have to live with.

"Phlip" <phlip_cpp@yahoo.com> wrote in message
news:pdZMc.1890$1t7.633@newssvr31.news.prodigy.com ...[color=blue]
> Dave Townsend wrote:
>[color=green]
> > In situations where an object may be passed or not, or may be present
> > or not, a pointer is needed.[/color]
>
> Read my post.
>
> I think I might be able to extend the NullObject concept to say not using[/color]
it[color=blue]
> violates the Liskov Substitution Principle...
>
> --
> Phlip
> http://industrialxp.org/community/bi...UserInterfaces
>
>[/color]


Phlip
Guest
 
Posts: n/a
#8: Jul 22 '05

re: Pointers vs References: A Question on Style


Dave Townsend wrote:
[color=blue]
> Agreed, but using a NullObject only relates to new classes, not
> legacy ones I have to live with.[/color]

Read /Working Effectively with Legacy Code/ by Mike Feathers.

Then think globally and act locally. One little NullObject at one interface
won't bring down the whole house of cards.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces


Desmond Liu
Guest
 
Posts: n/a
#9: Jul 22 '05

re: Pointers vs References: A Question on Style


JKop <NULL@NULL.NULL> wrote in news:zOWMc.5510$Z14.6835@news.indigo.ie:
[color=blue]
> There are 2 and only 2 situations in which I choose a pointer over a
> reference:
>
> 1) When it must be re-seated
>
> 2) When arrays are involved
>
>[color=green]
>> I understand the reasoning behind
>> using references--you avoid the cost of
>> creating a local object when you
>> pass an object by reference.[/color]
>
>
> Incorrect. The nature of today's computers (ie. stack and registers)
> still require a hidden pointer. (This is ofcourse where outline
> functions are involved).
>
>
> -JKop[/color]

Whoops. That was a typo. That should have read "avoid the cost of creating
a local object when you pass an object by _value_, as per Scott Meyer's
advice. Sorry.

Desmond
Joe C
Guest
 
Posts: n/a
#10: Jul 22 '05

re: Pointers vs References: A Question on Style



"Phlip" <phlip_cpp@yahoo.com> wrote in message
news:MCXMc.120$4D2.74@newssvr33.news.prodigy.com.. .[color=blue]
> C++ supports qualifications before their qualified types, such as "const
> SimCity &". I try to write expressions with the most important part first.
> There are also subtle technical reasons, in rare situations, to write
> "SimCity const &", with the const after its type.
>[/color]

Hi Phlip, can you elaborate on this? I've been using "const datatype &data"
rather than "datatype const &data". What are the differences between these
two semantic styles?




DaKoadMunky
Guest
 
Posts: n/a
#11: Jul 22 '05

re: Pointers vs References: A Question on Style


>One good style rule is to never return null, and never accept null as[color=blue]
>parameter.
>
>Follow that rule by passing in instead a Null Object. Consider this code:
>
>void funk(SimCity const * pCity)
>{
> if (pCity)
> pCity->throwParade();
>}
>
>Now contrast with this:
>
>class NullCity: public SimCity
>{
> public: /*virtual*/ void throwParade() {}
>};
>
>void funk(SimCity const & aCity)
>{
> aCity.throwParade();
>}[/color]

Two questions...

What if calling SimCity::throwParade requires the caller to ensure certain
preconditions are met? Suppose ensuring those preconditions is expensive. It
seems that using a NullCity here and not checking for it (or a 0 value) could
result in unnecessary code being executed.

What if the caller of SimCity::throwParade writes code that is dependent upon
the postconditions associated with SimCity::throwParade? I am not sure how a
NullCity can be reasonably substituted in this case. Because it is a "do
nothing" object it doesn't seem correct to have it guarantee postconditions nor
dor does it seem correct for calling code to respond as though an error was
present because postconditions were not met.

I am in the midst of reading about NullObject at
http://c2.com/cgi/wiki?NullObject. Maybe I will find the answer there. I am
curious as to your response though.

Thanks.




Phlip
Guest
 
Posts: n/a
#12: Jul 22 '05

re: Pointers vs References: A Question on Style


Joe C wrote:[color=blue]
>
> Phlip wrote:[/color]
[color=blue][color=green]
> > C++ supports qualifications before their qualified types, such as "const
> > SimCity &". I try to write expressions with the most important part[/color][/color]
first.[color=blue][color=green]
> > There are also subtle technical reasons, in rare situations, to write
> > "SimCity const &", with the const after its type.
> >[/color]
>
> Hi Phlip, can you elaborate on this? I've been using "const datatype[/color]
&data"[color=blue]
> rather than "datatype const &data". What are the differences between[/color]
these[color=blue]
> two semantic styles?[/color]

It's only style - the base type should go first, so you read it first when
you scan a line.

The only technical reason I can think of is this:

#define datatype someType*
//typedef someType * datatype;

Only the post-fixed 'const' works the same for each of those two different
ways to declare datatype.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces


Phlip
Guest
 
Posts: n/a
#13: Jul 22 '05

re: Pointers vs References: A Question on Style


DaKoadMunky wrote:
[color=blue][color=green]
> >void funk(SimCity const & aCity)
> >{
> > aCity.throwParade();
> >}[/color]
>
> Two questions...
>
> What if calling SimCity::throwParade requires the caller to ensure certain
> preconditions are met? Suppose ensuring those preconditions is expensive.[/color]
It[color=blue]
> seems that using a NullCity here and not checking for it (or a 0 value)[/color]
could[color=blue]
> result in unnecessary code being executed.[/color]

Uh, move those expensive things into delegates of SimCity. Call them
meetPreconditions(). Then give NullCity an empty implementation of that
method.

H. S. Lahman wrote this:

Responding to Phlip...
[color=blue]
> The Liskov Substitution Principle states (roughly) that users of[/color]
polymorphic[color=blue]
> types must not be required to detect which derived type responds to an
> interface.
>
> A thread on another newsgroup lead me to suspect this violates LSP:
>
> void funk(SimCity * pCity)
> {
> if (pCity != NULL)
> pCity->throwParade();
> }
>
> By that estimation, NULL pointers in interfacial C++ are history.
> NullObject - or better - is the way to go.[/color]

I agree with Wissler. Checking a NULL pointer is merely a check on
relationship conditionality, which is quite valid.

OTOH, one has to wonder why a NULL pointer is being passed to funk. If
anything funny is going on, the damage was already done in the caller,
such as:

Client::doIt (City* pCity)
{
SimCity* pSimCity; // subclass of City

pSimCity = dynamic_cast<SimCity>(pCity);
funk (pSimCity);
}


FWIW, I think this is just another example of why it is a bad idea to
pass object references except as a setter for a referential attribute.
Conditionality in relationships presents enough problems to the client
without combining it with temporary relationship instantiation.

*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

----8<-----------------------------------
[color=blue]
> What if the caller of SimCity::throwParade writes code that is dependent
> upon
> the postconditions associated with SimCity::throwParade? I am not sure
> how a
> NullCity can be reasonably substituted in this case. Because it is a "do
> nothing" object it doesn't seem correct to have it guarantee
> postconditions nor
> dor does it seem correct for calling code to respond as though an error
> was
> present because postconditions were not met.[/color]

You may want to post this to my thread on news:comp.object!

I know I would continue to test for null-ness where needed, and would
attempt to push those sensitive things into a delegate that naturally goes
away when the NullObject is around. But like the "pimpl idiom", NullObject
is the target of an emergency refactor, not a design goal by itself. I think
your sensitive things already violated LSP before replacing the pointer with
the NullObject.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces




David Rubin
Guest
 
Posts: n/a
#14: Jul 22 '05

re: Pointers vs References: A Question on Style


"Phlip" <phlip_cpp@yahoo.com> wrote in message news:<MCXMc.120$4D2.74@newssvr33.news.prodigy.com> ...[color=blue]
> DaKoadMunky wrote:
>[color=green][color=darkred]
> > >There are 2 and only 2 situations in which I choose a pointer over a
> > >reference:
> > >
> > >1) When it must be re-seated
> > >
> > >2) When arrays are involved[/color]
> >
> > Another possibility is when a function argument is optional. Pointers can[/color]
> be[color=green]
> > null whereas references cannot.[/color][/color]

Typically, you should pass parameters *by* *address*

1. whenever the parameter is going to be modified
e.g., int getValue(int *result, const my_Object& key);

2. whenever arrays are involved
e.g, int bubbleSort(int *array);

3. whenever you need to express an optional argument
e.g., my_Object::my_Object(int initialValue, an_Allocator = 0);

4. whenever you want to delegate ownership
e.g., objectVector.push_back(new my_Object(22));
void an_Allocator::deallocate(void *buffer);

4. when you want to pass a string
e.g., int lookup(const char *name);
[color=blue]
> One good style rule is to never return null, and never accept null as
> parameter.[/color]

This is a naive rule. For example, you want to return a pointer when
it is possible for a result to be invalid, undefined, or unset:

const my_Object *lookup(const char *name);

my_Object *my_Objet::singleton();

Obviously, you need to return by address when you return a dynamically
allocated object, as in a factory method.

As for *accepting* a null pointer argument, there is really no problem
with this as long as you *document* the expected behavior so that your
clients understand how to use your function:

int getValue(int *result, const my_Object& key);
// Load the value associated with the specified 'key'
// into the specified 'result'. Return 0 on success,
// and a non-zero value otherwise. The behavior is
// undefined unless 'result' is a valid pointer. Note
// that the value pointed to by 'result' is not altered
// if the function does not succeed.

Notice that "undefined" behavior means that you, the imlementor, can
deallocate a null or invalid pointer, 'assert' that the parameter is
not null, or whatever.
[color=blue]
> Follow that rule by passing in instead a Null Object. Consider this code:[/color]
[color=blue]
> void funk(SimCity const * pCity)
> {
> if (pCity)
> pCity->throwParade();
> }[/color]
[color=blue]
> Now contrast with this:[/color]
[color=blue]
> class NullCity: public SimCity
> {
> public: /*virtual*/ void throwParade() {}
> };[/color]
[color=blue]
> void funk(SimCity const & aCity)
> {
> aCity.throwParade();
> }[/color]

This may be completly unreasonable when working with third-party or
legacy code. Also, it makes it impossible to detect a usage violation
without doing a dynamic_cast on an argument with a polymorphic type.
For example, if it is not valid to pass a null SimCity object to
'funk', you should pass by address and 'assert' that the parameter is
not null. If it is not *possible* to pass a null SimCity object to
'funk', you should pass by reference, and catch errors at compile
time.
[color=blue]
> C++ supports qualifications before their qualified types, such as "const
> SimCity &". I try to write expressions with the most important part first.
> There are also subtle technical reasons, in rare situations, to write
> "SimCity const &", with the const after its type.[/color]

What technical reasons? Style is not "technical"...

/david
Phlip
Guest
 
Posts: n/a
#15: Jul 22 '05

re: Pointers vs References: A Question on Style


> > One good style rule is to never return null, and never accept null as[color=blue][color=green]
> > parameter.[/color][/color]

David Rubin did not know his peril when he uttered:
[color=blue]
> This is a naive rule. For example, you want to return a pointer when
> it is possible for a result to be invalid, undefined, or unset:[/color]

All rules are naive. Calling that rule naive is naive.
[color=blue]
> const my_Object *lookup(const char *name);
>
> my_Object *my_Objet::singleton();[/color]

You need to study Barton & Nackman's Fallible<> class template, from their
/Scientific & Engineering in C++ something/ book.
[color=blue]
> Obviously, you need to return by address when you return a dynamically
> allocated object, as in a factory method.[/color]

That is non-obvious. If the factory throws when it can't allocate, it can't
return NULL, hence the reason for pointing goes away. It could honestly
return a reference.

Rule 1: Prefer references to pointers unless you need pointers' special
abilities.

Rule 2: Avoid the need for pointers' special abilities.

I recently wrote a dialog box, in WTL (on MS Windows) that stores customer
names in a list box, and names and address in edit fields. The edit field
for the State is a combo box. The dialog box stores the name list in XML
(via MSXML via COM), and the list box displays tabs correctly as columns.
The edit fields link to the XML via MVC. The dialog box can localize to
Sanskrit, and can display a cancellable progress bar based on a window
timer.

The only * in the program are for passing constant strings into low-level
functions, and inside one auto_ptr<>. Otherwise, no pointers. (And remember
WTL is a healthier library than MFC!)
[color=blue]
> As for *accepting* a null pointer argument, there is really no problem
> with this as long as you *document* the expected behavior so that your
> clients understand how to use your function:
>
> int getValue(int *result, const my_Object& key);
> // Load the value associated with the specified 'key'
> // into the specified 'result'. Return 0 on success,
> // and a non-zero value otherwise. The behavior is
> // undefined unless 'result' is a valid pointer. Note
> // that the value pointed to by 'result' is not altered
> // if the function does not succeed.[/color]

Comments suck. int result should be a full-fledged object that enforces
those behaviors, if they are important.
[color=blue][color=green]
> > void funk(SimCity const & aCity)
> > {
> > aCity.throwParade();
> > }[/color]
>
> This may be completly unreasonable when working with third-party or
> legacy code.[/color]

It may be the only salvation for such code. Obviously you can't change
someone's opaque function.

When un-f***ing-up legacy code, the ability to slip new polymorphic
behaviors into its tangled code is priceless. Introducing the ability to
polymorph a SimCity carries many more benefits than just introducing
NullObjects.

(Read /working effectively with legacy code/ by Mike Feathers.)
[color=blue]
> Also, it makes it impossible to detect a usage violation
> without doing a dynamic_cast on an argument with a polymorphic type.
> For example, if it is not valid to pass a null SimCity object to
> 'funk', you should pass by address and 'assert' that the parameter is
> not null. If it is not *possible* to pass a null SimCity object to
> 'funk', you should pass by reference, and catch errors at compile
> time.[/color]

That sounds like an argument for NullObject.

Compile time checking only catches some errors. All a NULL pointer needs to
accidentally become an undefinable reference is a single dereferencing star
* in the wrong spot.

If you are that frantic about them, use wall-to-wall unit tests. BTW my
Sanskrit dialog was written via test-first on every single feature. The test
cases can also record screen shots of the dialog's various locale skins, and
can record animations of the progress bar.
[color=blue][color=green]
> > C++ supports qualifications before their qualified types, such as "const
> > SimCity &". I try to write expressions with the most important part[/color][/color]
first.[color=blue][color=green]
> > There are also subtle technical reasons, in rare situations, to write
> > "SimCity const &", with the const after its type.[/color]
>
> What technical reasons? Style is not "technical"...[/color]

No shit. Style is not technical? Damn, am I ever glad I clicked on this post
today! Woah, you sure set me straight on that one!

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces


Richard Herring
Guest
 
Posts: n/a
#16: Jul 22 '05

re: Pointers vs References: A Question on Style


In message <82b37be.0407261657.2d16c4a0@posting.google.com> , David Rubin
<davidrubin@warpmail.net> writes[color=blue]
>"Phlip" <phlip_cpp@yahoo.com> wrote in message
>news:<MCXMc.120$4D2.74@newssvr33.news.prodigy.com >...[color=green]
>> DaKoadMunky wrote:
>>[color=darkred]
>> > >There are 2 and only 2 situations in which I choose a pointer over a
>> > >reference:
>> > >
>> > >1) When it must be re-seated
>> > >
>> > >2) When arrays are involved
>> >
>> > Another possibility is when a function argument is optional. Pointers can[/color]
>> be[color=darkred]
>> > null whereas references cannot.[/color][/color][/color]

But default-constructed "null" objects can often be passed by reference
to give the same effect.[color=blue]
>
>Typically, you should pass parameters *by* *address*
>
>1. whenever the parameter is going to be modified
> e.g., int getValue(int *result, const my_Object& key);[/color]

But a pointer might be null or point to something that's been deleted.
If you pass by non-const reference, you don't have to worry about that.[color=blue]
>
>2. whenever arrays are involved
> e.g, int bubbleSort(int *array);[/color]

Well, yes, but why use arrays? (why write your own bubblesort? why not
pass two iterators to it? ...)[color=blue]
>
>3. whenever you need to express an optional argument
> e.g., my_Object::my_Object(int initialValue, an_Allocator = 0);[/color]

Except when it's more appropriate to pass it by value. Or reference
(e.g. see how the STL passes allocators to constructors.)[color=blue]
>
>4. whenever you want to delegate ownership
> e.g., objectVector.push_back(new my_Object(22));
> void an_Allocator::deallocate(void *buffer);[/color]

void* ? Real allocators mostly use Allocator::pointer.
[color=blue]
>
>4. when you want to pass a string
> e.g., int lookup(const char *name);
>[/color]
Same as the array case. But why use array of const char when you have
std::string?


--
Richard Herring
David Rubin
Guest
 
Posts: n/a
#17: Jul 22 '05

re: Pointers vs References: A Question on Style


"Phlip" <phlip_cpp@yahoo.com> wrote in message news:<69jNc.2858$dM2.1344@newssvr17.news.prodigy.c om>...[color=blue][color=green][color=darkred]
> > > One good style rule is to never return null, and never accept null as
> > > parameter.[/color][/color]
>
> David Rubin did not know his peril when he uttered:
>[color=green]
> > This is a naive rule. For example, you want to return a pointer when
> > it is possible for a result to be invalid, undefined, or unset:[/color]
>
> All rules are naive. Calling that rule naive is naive.
>[color=green]
> > const my_Object *lookup(const char *name);
> >
> > my_Object *my_Objet::singleton();[/color]
>
> You need to study Barton & Nackman's Fallible<> class template, from their
> /Scientific & Engineering in C++ something/ book.
>[color=green]
> > Obviously, you need to return by address when you return a dynamically
> > allocated object, as in a factory method.[/color]
>
> That is non-obvious. If the factory throws when it can't allocate, it can't
> return NULL, hence the reason for pointing goes away. It could honestly
> return a reference.[/color]

If your function throws an exception, it doesn't matter what it
returns; you need to deal with an exception. There are also situations
in which you do not want to support exceptions (possibly due to
run-time considerations). Furthermore, it is a good idea to follow the
rule that if you have a pointer, you should use a pointer. For
example, what do you gain from this?

Type& my_Factory::allocate() {
Type *obj = new Type;
return *obj;
}

You are also left with the connundrum of writing the analogous
'deallocate' method:

void my_Factory::deallocate(Type& obj);
// 'obj' is altered even though it is passed by reference
and
factory.deallocate(object); // unconventional

or

void my_Factory::deallocate(Type *obj); // not symmetric to
'allocate'
and
factory.deallocate(&object);
// How do you know 'object' is dynamically allocated?

[snip][color=blue][color=green]
> > As for *accepting* a null pointer argument, there is really no problem
> > with this as long as you *document* the expected behavior so that your
> > clients understand how to use your function:
> >
> > int getValue(int *result, const my_Object& key);
> > // Load the value associated with the specified 'key'
> > // into the specified 'result'. Return 0 on success,
> > // and a non-zero value otherwise. The behavior is
> > // undefined unless 'result' is a valid pointer. Note
> > // that the value pointed to by 'result' is not altered
> > // if the function does not succeed.[/color]
>
> Comments suck. int result should be a full-fledged object that enforces
> those behaviors, if they are important.[/color]

Really? What are the semantics of this function?

my_Result compute(my_Value& v1, my_Value& v2);

Comments are the *only* way most clients can understand how code
works. Most people speak better English (for example) than C++.

[color=blue][color=green][color=darkred]
> > > C++ supports qualifications before their qualified types, such as "const
> > > SimCity &". I try to write expressions with the most important part[/color][/color]
> first.[color=green][color=darkred]
> > > There are also subtle technical reasons, in rare situations, to write
> > > "SimCity const &", with the const after its type.[/color]
> >
> > What technical reasons? Style is not "technical"...[/color]
>
> No shit. Style is not technical? Damn, am I ever glad I clicked on this post
> today! Woah, you sure set me straight on that one![/color]

Can you please tell us what you had in mind when you wrote the
original comment, rather than unleash your misguided sarcasm? Several
people here seem interested.

/david
David Rubin
Guest
 
Posts: n/a
#18: Jul 22 '05

re: Pointers vs References: A Question on Style


Richard Herring <junk@[127.0.0.1]> wrote in message news:<quECHlDO2hBBFwhX@baesystems.com>...

[snip][color=blue][color=green]
> >Typically, you should pass parameters *by* *address*
> >
> >1. whenever the parameter is going to be modified
> > e.g., int getValue(int *result, const my_Object& key);[/color]
>
> But a pointer might be null or point to something that's been deleted.
> If you pass by non-const reference, you don't have to worry about that.[/color]

You are suggesting

int getValue(int& result, const my_Object& key);

which would be called like this

int rc = getValue(numBeans, pod);

This does not read well since it is difficult to tell what parameter
is being modified. See C++PL 3ed 5.5.

[snip][color=blue][color=green]
> >4. whenever you want to delegate ownership
> > e.g., objectVector.push_back(new my_Object(22));
> > void an_Allocator::deallocate(void *buffer);[/color]
>
> void* ? Real allocators mostly use Allocator::pointer.[/color]

Yes, this is a typo. And, this is not an 'Allocator', it's
'an_Allocator'. But the point is the same; you still return a pointer.
[color=blue][color=green]
> >4. when you want to pass a string
> > e.g., int lookup(const char *name);
> >[/color]
> Same as the array case. But why use array of const char when you have
> std::string?[/color]

This is a subtle point. You want to choose a lowest common
denomentator type. For example, an interface such as

int lookup(const std::string& name);

*forces* clients to use 'std::string'; it's not optional. You client
might prefer to use 'Acme::string', or might not be able to use STL.
(This does happen sometimes...). In any case, with the 'const char *'
interface, clients *can* use 'std::string' or any other string type
which converts to 'const char *'.

This begs the question of whether or not you should *return* a
'std::string' (reference) or a 'const char *'... /david
Phlip
Guest
 
Posts: n/a
#19: Jul 22 '05

re: Pointers vs References: A Question on Style


David Rubin wrote:
[color=blue]
> If your function throws an exception, it doesn't matter what it
> returns; you need to deal with an exception. There are also situations
> in which you do not want to support exceptions (possibly due to
> run-time considerations). Furthermore, it is a good idea to follow the
> rule that if you have a pointer, you should use a pointer. For
> example, what do you gain from this?
>
> Type& my_Factory::allocate() {
> Type *obj = new Type;
> return *obj;
> }
>
> You are also left with the connundrum of writing the analogous
> 'deallocate' method:
>
> void my_Factory::deallocate(Type& obj);
> // 'obj' is altered even though it is passed by reference
> and
> factory.deallocate(object); // unconventional
>
> or
>
> void my_Factory::deallocate(Type *obj); // not symmetric to
> 'allocate'
> and
> factory.deallocate(&object);
> // How do you know 'object' is dynamically allocated?[/color]

Add a smart shared pointer to the above - if your design truly needs 'new'.
[color=blue][color=green]
> > Comments suck. int result should be a full-fledged object that enforces
> > those behaviors, if they are important.[/color]
>
> Really? What are the semantics of this function?
>
> my_Result compute(my_Value& v1, my_Value& v2);
>
> Comments are the *only* way most clients can understand how code
> works. Most people speak better English (for example) than C++.[/color]

I would work on making that function's unit test self-documenting before
working on its comments. You can't test a comment.
[color=blue][color=green]
> > C++ supports qualifications before their qualified types, such as "const
> > SimCity &". I try to write expressions with the most important part
> > first.
> > There are also subtle technical reasons, in rare situations, to write
> > "SimCity const &", with the const after its type.[/color][/color]

I'm not sure but there might be more reasons than this:

#define datatype someType*
//typedef someType * datatype;

Only the post-fixed 'const' works the same for each of those two different
ways to declare datatype.

Insert the standard newsgroup screed against #define here.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces



Richard Herring
Guest
 
Posts: n/a
#20: Jul 22 '05

re: Pointers vs References: A Question on Style


In message <82b37be.0407270845.5841d675@posting.google.com> , David Rubin
<davidrubin@warpmail.net> writes[color=blue]
>Richard Herring <junk@[127.0.0.1]> wrote in message
>news:<quECHlDO2hBBFwhX@baesystems.com>...
>
>[snip][color=green][color=darkred]
>> >Typically, you should pass parameters *by* *address*
>> >
>> >1. whenever the parameter is going to be modified
>> > e.g., int getValue(int *result, const my_Object& key);[/color]
>>
>> But a pointer might be null or point to something that's been deleted.
>> If you pass by non-const reference, you don't have to worry about that.[/color]
>
>You are suggesting
>
> int getValue(int& result, const my_Object& key);
>
>which would be called like this
>
> int rc = getValue(numBeans, pod);
>
>This does not read well since it is difficult to tell what parameter
>is being modified. See C++PL 3ed 5.5.[/color]

....which says, inter alia, 'Consequently "plain" reference arguments
should be used only where the name of the function gives a strong hint
that the reference argument is modified.'

"Get" in the function's name _would_ be such a hint were it not for the
fact that the function returns _another_ value as its return value. I'd
be inclined to question why. If it's an error indicator, perhaps you'd
be better throwing an exception instead of returning a code which has to
be tested.
[color=blue]
>[snip][color=green][color=darkred]
>> >4. whenever you want to delegate ownership
>> > e.g., objectVector.push_back(new my_Object(22));
>> > void an_Allocator::deallocate(void *buffer);[/color]
>>
>> void* ? Real allocators mostly use Allocator::pointer.[/color]
>
>Yes, this is a typo. And, this is not an 'Allocator', it's
>'an_Allocator'. But the point is the same; you still return a pointer.
>[color=green][color=darkred]
>> >4. when you want to pass a string
>> > e.g., int lookup(const char *name);
>> >[/color]
>> Same as the array case. But why use array of const char when you have
>> std::string?[/color]
>
>This is a subtle point. You want to choose a lowest common
>denomentator type. For example, an interface such as
>
> int lookup(const std::string& name);
>
>*forces* clients to use 'std::string'; it's not optional. You client
>might prefer to use 'Acme::string',[/color]

So they have to write lookup(std::string(acmeString.c_str())). That's
not so terrible.
[color=blue]
>or might not be able to use STL.[/color]

If we're talking about standard (hosted) C++, I think that possibility
is somewhat academic.
[color=blue]
>(This does happen sometimes...). In any case, with the 'const char *'
>interface, clients *can* use 'std::string' or any other string type
>which converts to 'const char *'.[/color]

But now they can't pass a string which contains '\0'. This happens
sometimes, too.[color=blue]
>
>This begs the question of whether or not you should *return* a
>'std::string' (reference) or a 'const char *'... /david[/color]

Neither. Return a std::string by value and you have no need to argue
about ownership or lifetime of the result.
--
Richard Herring
DaKoadMunky
Guest
 
Posts: n/a
#21: Jul 22 '05

re: Pointers vs References: A Question on Style


>But a pointer might be null or point to something that's been deleted.[color=blue]
>If you pass by non-const reference, you don't have to worry about that.[/color]

Careless coding could lead to a reference that refers to a deleted object.

void SomeFunc(int)
{
}

int main()
{
int * intPtr = new int(0);
int & intRef = *intPtr;

delete intPtr;

SomeFunc(intRef);

return 0;
}

And of course there is also the "returning a reference to a local" that I think
is discussed in the FAQ.




Richard Herring
Guest
 
Posts: n/a
#22: Jul 22 '05

re: Pointers vs References: A Question on Style


In message <20040727222225.11752.00002350@mb-m11.aol.com>, DaKoadMunky
<dakoadmunky@aol.com> writes[color=blue][color=green]
>>But a pointer might be null or point to something that's been deleted.
>>If you pass by non-const reference, you don't have to worry about that.[/color]
>
>Careless coding could lead to a reference that refers to a deleted object.[/color]

But you have to use pointers to achieve it.[color=blue]
>
>void SomeFunc(int)
>{
>}
>
>int main()
>{
> int * intPtr = new int(0);
> int & intRef = *intPtr;
>
> delete intPtr;
>
> SomeFunc(intRef);
>
> return 0;
>}
>
>And of course there is also the "returning a reference to a local" that I think
>is discussed in the FAQ.
>[/color]
Indeed. But here we're talking about passing references _in_, not _out_.
--
Richard Herring
Niklas Borson
Guest
 
Posts: n/a
#23: Jul 22 '05

re: Pointers vs References: A Question on Style


"Phlip" <phlip_cpp@yahoo.com> wrote in message news:<tNvNc.930$uC7.399@newssvr19.news.prodigy.com >...[color=blue][color=green][color=darkred]
> > >
> > > There are also subtle technical reasons, in rare situations, to write
> > > "SimCity const &", with the const after its type.[/color][/color][/color]

There's always:

char const* const days[] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

The rule is that a cv-qualifier modifies the thing to its left, unless
it's at the beginning of the type specifier in which case it modifies
the thing to its right.

Since it is sometimes necessary to put the const after the thing it
modifies (as in the second const above), it is reasonable to argue
that one should *always* do so, for reasons of consistency.

There's also a pedalogical argument for the put-const-after style.
The habit of putting const first creates the misleading impression
that const modifies the thing to its right, wheras this is actually
the exception. One must unlearn this in order to correctly write
declarations like the one above.

Despite all of the above, putting const first is certainly the more
conventional style. See the C++ standard document for example.
Doing otherwise just "feels wrong" to me. Perhaps it has something
to do with the fact that adjectives in English precede the nouns
they modify, or maybe old habits just die hard.

BTW, thanks for the interesting discussion about null pointers. I've
found the arguments quite stimulating on both sides.
David Rubin
Guest
 
Posts: n/a
#24: Jul 22 '05

re: Pointers vs References: A Question on Style


"Phlip" <phlip_cpp@yahoo.com> wrote in message news:<tNvNc.930$uC7.399@newssvr19.news.prodigy.com >...

[snip][color=blue][color=green][color=darkred]
> > > Comments suck. int result should be a full-fledged object that enforces
> > > those behaviors, if they are important.[/color]
> >
> > Really? What are the semantics of this function?
> >
> > my_Result compute(my_Value& v1, my_Value& v2);
> >
> > Comments are the *only* way most clients can understand how code
> > works. Most people speak better English (for example) than C++.[/color]
>
> I would work on making that function's unit test self-documenting before
> working on its comments. You can't test a comment.[/color]

Firstly, how can you write a unit test if you don't specify the
semantics of the function? Secondly, how do you expect clients of your
software to understand how it works? By reading source code? No. They
will look at the header file, since that, and the library, is all they
have.

So, in fact, you *only* test comments! For example,

bool operator<(const IPv4Address& lhs, const IPv4Address& rhs);

What does this function do?

1. Behavior

// Return true if the 'lhs' object is less than the 'rhs'
object,
// and false otherwise.

Okay, how do you construct a unit test around this behavioral
description? What values should you choose? What should the unit test
look like?

2. Definition of Terms

// 'lhs' is less than 'rhs' if its address is less than that
// of 'rhs', or if its address is equal to that of 'rhs' and
// its port number is less than that of 'rhs'.

This is a lot clearer. Now we can at least choose test values and know
what result to expect. But why should 'IPv4Address' objects be ordered
in this way? It's rather arbitrary. We could just as easily have
ordered them by port number. In fact, some clients might prefer such
an ordering if they want to group "connections" by their service
endpoint (i.e., group 'IPv4Address' objects representing connections
to various machines by port number). Well, your clients have a right
to know your motivations.

3. Note That

// Note that this arbitrary ordering of 'IPv4Address' objects
// is chosen primariliy to facilitate interoperability with
// STL Sorted Associative Containers.

Now that you've sufficiently *documented* the semantics of your
function, and your motivations, you can test your function:

Unit Test (in a separate .cpp file with a 'main')

// TESTING LESS THAN (<) OPERATOR
//
// Concerns:
// Subtle differences in IP address and port number of two
'IPv4Address'
// objects are detected by comparison with the less-than
operator.
//
// Plan:
// Specify a set S of 'IPv4Address' objects each having
variations in
// the IP address and/or port number. Compare each pair (u, v)
in the
// cross product S x S, such that u != v.
//
// Create a 'std::vector', 'W', of 'IPv4Address' objects that
acts as a
// control. Create a copy of 'W' named 'X'. Randomly permute
'X', and
// verify that 'X' is different than 'W'. Sort 'X' using
'std::sort',
// implicitly exercising the defined less-than operator, and
verify that
// 'X' is the same as 'W'.
//
// Testing:
// bool operator<(const IPv4Address& lhs, const IPv4Address&
rhs);

Okay. Now you know exactly the semantics of the function and the
structure of the unit test. You also know that your motivations are
validated by a concrete example. I have not written *any* code. The
function and the test case are *documented*, not "self documenting."

/david
Bob Hairgrove
Guest
 
Posts: n/a
#25: Jul 22 '05

re: Pointers vs References: A Question on Style


On Sun, 25 Jul 2004 22:30:55 GMT, Desmond Liu <dliu7647nospam@shaw.ca>
wrote:
[color=blue]
>I've read articles like Scott Meyer's EC++ (Item 22) that advocate the use
>of references when passing parameters. I understand the reasoning behind
>using references--you avoid the cost of creating a local object when you
>pass an object by reference.
>
>But why use a reference? Is there any inherent advantage of using a
>reference over using a pointer? My workplace discourages the use of
>pointers when it comes to parameter passing. They always prefer references.
>[/color]
[snip]

There are always situations where one will be preferred over the
other, but in general, go with references. A reference will always
point to a valid object (unless there is evil trickery at play),
whereas a pointer might not. And aside from checking for NULL, the
function has no way of knowing whether the pointer is valid or not.

An example of "evil trickery":

class A{};
void f(A&){}
int main()
{
A* pa = new A();
A& ra = *pa;
delete pa;
f(ra);
return 0;
}

This should never happen in real life. Unfortunately, it sometimes
does ... but passing pointers instead of references isn't going to
help you when it does happen.

--
Bob Hairgrove
NoSpamPlease@Home.com
DaKoadMunky
Guest
 
Posts: n/a
#26: Jul 22 '05

re: Pointers vs References: A Question on Style


>An example of "evil trickery":[color=blue]
>
>class A{};
>void f(A&){}
>int main()
>{
> A* pa = new A();
> A& ra = *pa;
> delete pa;
> f(ra);
> return 0;
>}[/color]

Isn't it possible that this could also occur though not out of malice but just
carelessness?

Suppose many statements separated the statements presented and our poor little
programmer got confused.

It does seem reasonable that the ordering of the delete and the use of the
reference could just be accidental.

I guess I am just being picky about phrasing.


JKop
Guest
 
Posts: n/a
#27: Jul 22 '05

re: Pointers vs References: A Question on Style


Bob Hairgrove posted:
[color=blue]
> On Sun, 25 Jul 2004 22:30:55 GMT, Desmond Liu[/color]
<dliu7647nospam@shaw.ca>[color=blue]
> wrote:
>[color=green]
>>I've read articles like Scott Meyer's EC++ (Item 22)[/color][/color]
that advocate the[color=blue][color=green]
>>use of references when passing parameters. I understand[/color][/color]
the reasoning[color=blue][color=green]
>>behind using references--you avoid the cost of creating[/color][/color]
a local object[color=blue][color=green]
>>when you pass an object by reference.
>>
>>But why use a reference? Is there any inherent advantage[/color][/color]
of using a[color=blue][color=green]
>>reference over using a pointer? My workplace discourages[/color][/color]
the use of[color=blue][color=green]
>>pointers when it comes to parameter passing. They always[/color][/color]
prefer[color=blue][color=green]
>>references.
>>[/color]
> [snip]
>
> There are always situations where one will be preferred[/color]
over the[color=blue]
> other, but in general, go with references. A reference[/color]
will always[color=blue]
> point to a valid object (unless there is evil trickery[/color]
at play),[color=blue]
> whereas a pointer might not. And aside from checking for[/color]
NULL, the[color=blue]
> function has no way of knowing whether the pointer is[/color]
valid or not.[color=blue]
>
> An example of "evil trickery":
>
> class A{};
> void f(A&){}
> int main()
> {
> A* pa = new A();
> A& ra = *pa;
> delete pa;
> f(ra);
> return 0;
> }
>
> This should never happen in real life. Unfortunately, it[/color]
sometimes[color=blue]
> does ... but passing pointers instead of references[/color]
isn't going to[color=blue]
> help you when it does happen.
>
> --
> Bob Hairgrove
> NoSpamPlease@Home.com[/color]


That's not evil, this is:


int& candy(*reintepret_cast<int*>(8742));

candy = 5;


-JKop
Closed Thread