Pointers vs References: A Question on Style

D

DaKoadMunky

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.

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.
 
R

Richard Herring

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

But you have to use pointers to achieve it.
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.
Indeed. But here we're talking about passing references _in_, not _out_.
 
N

Niklas Borson

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.
 
D

David Rubin

[snip]
I would work on making that function's unit test self-documenting before
working on its comments. You can't test a comment.

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
 
B

Bob Hairgrove

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.
[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.
 
D

DaKoadMunky

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;
}

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.
 
J

JKop

Bob Hairgrove posted:
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.
[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.


That's not evil, this is:


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

candy = 5;


-JKop
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top