By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,668 Members | 1,481 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,668 IT Pros & Developers. It's quick & easy.

Pass-by-reference instead of pass-by-pointer = a bad idea?

P: n/a
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

/H
Jul 23 '05 #1
Share this Question
Share on Google+
110 Replies


P: n/a
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

/H


That is exactly the right way to do it. I'd go so far as to say always
prefer a reference over a pointer unless you have an explicit need for a
pointer (i.e. it needs to be reseated for some reason and/or NULL has a
useful meaning). The reason being pretty much the same that you stated.
References are (for me at least) easier to work with, and there is no
worry of accidentally trying to access an object through a "NULL reference".

-Alan
Jul 23 '05 #2

P: n/a
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

/H


Unfortunately, there are different vantage points from which we view a
function: declaration, definition and invocation. Each has it's own
exposed and hidden information. It has been argued that passing a pointer
is more explicit, and makes the code easier to read. I tend to agree.

AFAIK, you *can* pass a null to func() in your example, and the compiler
will accept it. Your code will segfault when you do so. If you pass a
pointer, you can check for null, before accessing it. I, therefore,
suggest using a pointer instead of a reference.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #3

P: n/a
Steven T. Hatton wrote:
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.
The above paragraph is correct. Attempting to pass ANYTHING except
a ref to an existing instance of the required type will cause a
compile-time error. Unless there is some specific reason to pass a
pointer, using ref's is usually preferred.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

/H


Unfortunately, there are different vantage points from which we view a
function: declaration, definition and invocation. Each has it's own
exposed and hidden information. It has been argued that passing a pointer
is more explicit, and makes the code easier to read. I tend to agree.

AFAIK, you *can* pass a null to func() in your example, and the compiler
will accept it. Your code will segfault when you do so. If you pass a
pointer, you can check for null, before accessing it. I, therefore,
suggest using a pointer instead of a reference.


If a function takes a ref, then NULL can not be passed.
Attempting to pass NULL causes a compile error.
For example:

#include <iostream>

struct Stuff
{
int a;
double b;
};

void func(Stuff& obj)
{
obj.a = 1;
}

int main()
{
Stuff s;

func(s);
func(0); // causes a compile error

return 0;
}

Larry
Jul 23 '05 #4

P: n/a
Larry I Smith wrote:
Steven T. Hatton wrote:
Mr A wrote: [...]
I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.
The above paragraph is correct. Attempting to pass ANYTHING except
a ref to an existing instance of the required type will cause a
compile-time error. Unless there is some specific reason to pass a
pointer, using ref's is usually preferred.


By whom?
Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

/H


Unfortunately, there are different vantage points from which we view a
function: declaration, definition and invocation. Each has it's own
exposed and hidden information. It has been argued that passing a
pointer is more explicit, and makes the code easier to read. I tend to
agree.

AFAIK, you *can* pass a null to func() in your example, and the compiler
will accept it. Your code will segfault when you do so. If you pass a
pointer, you can check for null, before accessing it. I, therefore,
suggest using a pointer instead of a reference.


If a function takes a ref, then NULL can not be passed.
Attempting to pass NULL causes a compile error.
For example:

#include <iostream>

struct Stuff
{
int a;
double b;
};

void func(Stuff& obj)
{
obj.a = 1;
}

int main()
{
Stuff s;

func(s);
func(0); // causes a compile error

return 0;
}

Larry


In your example, you are not trying to pass null, you are trying to pass a
literal. That results in the attempt to create a temporary object of type
int and assign it to the non-const reference. This, however, will compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}

I know of two companies who have concluded that passing by reference is, in
general, a bad choice. Trolltech, and SuSE.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #5

P: n/a
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:as********************@speakeasy.net

In your example, you are not trying to pass null, you are trying to
pass a literal.
He is passing NULL which is the same as 0.
That results in the attempt to create a temporary
object of type int and assign it to the non-const reference. This,
however, will compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}


Dereferencing a NULL pointer is undefined behaviour by section 8.3.2/4.
When I run your code, the program crashes.

--
John Carson

Jul 23 '05 #6

P: n/a
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:as********************@speakeasy.net

AFAIK, you *can* pass a null to func() in your example, and the
compiler will accept it. Your code will segfault when you do so.
If you pass a pointer, you can check for null, before accessing it.
I, therefore, suggest using a pointer instead of a reference.


I missed this bit. It seems you are aware of the problem.

--
John Carson
Jul 23 '05 #7

P: n/a
Steven T. Hatton wrote:
Larry I Smith wrote:
Steven T. Hatton wrote:
Mr A wrote: [...]I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

The above paragraph is correct. Attempting to pass ANYTHING except
a ref to an existing instance of the required type will cause a
compile-time error. Unless there is some specific reason to pass a
pointer, using ref's is usually preferred.


By whom?
Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

/H

Unfortunately, there are different vantage points from which we view a
function: declaration, definition and invocation. Each has it's own
exposed and hidden information. It has been argued that passing a
pointer is more explicit, and makes the code easier to read. I tend to
agree.

AFAIK, you *can* pass a null to func() in your example, and the compiler
will accept it. Your code will segfault when you do so. If you pass a
pointer, you can check for null, before accessing it. I, therefore,
suggest using a pointer instead of a reference.


If a function takes a ref, then NULL can not be passed.
Attempting to pass NULL causes a compile error.
For example:

#include <iostream>

struct Stuff
{
int a;
double b;
};

void func(Stuff& obj)
{
obj.a = 1;
}

int main()
{
Stuff s;

func(s);
func(0); // causes a compile error

return 0;
}

Larry


In your example, you are not trying to pass null, you are trying to pass a
literal. That results in the attempt to create a temporary object of type
int and assign it to the non-const reference. This, however, will
compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}

I know of two companies who have concluded that passing by reference is,
in
general, a bad choice. Trolltech, and SuSE.

Obvious exceptions are:

std::ostream& print(std::ostream& out) const {...}

and when passing a const reference:

int foo(const BigObject& bo){}
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #8

P: n/a
John Carson wrote:
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:as********************@speakeasy.net

In your example, you are not trying to pass null, you are trying to
pass a literal.


He is passing NULL which is the same as 0.


'0', when it appears in your code, is a literal. If the reference were
const, the code /would/ compile.

#include <string>
std::string cfunc(const std::string& s) { return s; }
int main() {
cfunc(0);
}

It still has a problem. The above aborts when executed. That's one better
than a segfault, but not typically what I want from a program.
That results in the attempt to create a temporary
object of type int and assign it to the non-const reference. This,
however, will compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}


Dereferencing a NULL pointer is undefined behaviour by section 8.3.2/4.
When I run your code, the program crashes.


Yes, it segfaults. That was my point.

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #9

P: n/a
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?


That looks like a very good idea to me, and IIRC, the FAQ agrees. IMHO,
it's more than a matter of style; it's also a matter of safety. If a
parameter should never be null, then don't give it the chance.

Kristo
Jul 23 '05 #10

P: n/a
Why make every little routine test over and over again something that
isn't to ever happen?

The question people ask is, IMO, the wrong one.
People ask: When should I pass by reference?
The right question is "When should I pass by pointer?"

and the answer is "Whenever you want to allow a pointer-to-nothing
(i.e. 0)"
which is in my experience almost never.

I go one step further:
Pass by const reference unless the object may change.
This way when you call some code the intent is crystal clear.

I don't buy the argument that someone might then dereference a null
pointer and thus you always have to protect your code. Your interface
is a contract. At least with references you are making your intent
clear. Pass by pointer and you are saying "You're allowed to pass 0".
Too often if you rely on this in other people's code you'll be
surprised by seg faults because they did not handle being passed 0 --
they really meant it had to point to something.

You rely on other things in the contract: that the kind of object is
the kind you ask for (no static_cast downcasting to the wrong type or
your program will crash), that the relationships between objects is set
up, and so forth. For clarity of code and ease of maintainability I've
found passing by reference (const and non-const) leads to far clearer,
more maintainable and more robust code. Adding null pointer checks all
over the place instead of only in the places where the pointers can be
0 hides programmer intent while adding noise to the program and slowing
runtime. So why do it?

Stuart

Jul 23 '05 #11

P: n/a
Kristo wrote:
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?


That looks like a very good idea to me, and IIRC, the FAQ agrees. IMHO,
it's more than a matter of style; it's also a matter of safety. If a
parameter should never be null, then don't give it the chance.

Kristo


This is one man's opinion:
http://doc.trolltech.com/qq/qq13-apis.html
Pointers or References?

Which is best for out-parameters, pointers or references?

void getHsv(int *h, int *s, int *v) const
void getHsv(int &h, int &s, int &v) const
Most C++ books recommend references whenever possible, according to the
general perception that references are "safer and nicer" than pointers. In
contrast, at Trolltech, we tend to prefer pointers because they make the
user code more readable. Compare:

color.getHsv(&h, &s, &v);
color.getHsv(h, s, v);
Only the first line makes it clear that there's a high probability that h,
s, and v will be modified by the function call.

http://en.wikipedia.org/wiki/Matthias_Ettrich
http://www.kde.org/

When I started working with the KDE, I could download it with a 28.8 modem,
build and install it in a matter of a few minutes on a Pentium. It now
occupies 1.2 G on my harddrive. That may (does) represent some bloat, but
it also represents unquestionable progress. Ettrich is a man who
understands the three principles of good software design. User interface,
user interface, and user interface.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #12

P: n/a
Ian
Kristo wrote:
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ). The code
becomes somewhat more self-documenting.

Any comments on why this could be a bad idea or do you think it's just
a matter of taste?

That looks like a very good idea to me, and IIRC, the FAQ agrees. IMHO,
it's more than a matter of style; it's also a matter of safety. If a
parameter should never be null, then don't give it the chance.

And passing by reference does this? I don't think so.

Ian
Jul 23 '05 #13

P: n/a
Steven T. Hatton wrote:
John Carson wrote:
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:as********************@speakeasy.net
In your example, you are not trying to pass null, you are trying to
pass a literal.He is passing NULL which is the same as 0.


'0', when it appears in your code, is a literal. If the reference were
const, the code /would/ compile.


In C++ NULL is zero (0).

#include <string>
std::string cfunc(const std::string& s) { return s; }
int main() {
cfunc(0);
}

It still has a problem. The above aborts when executed. That's one better
than a segfault, but not typically what I want from a program.
That results in the attempt to create a temporary
object of type int and assign it to the non-const reference. This,
however, will compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}

Dereferencing a NULL pointer is undefined behaviour by section 8.3.2/4.
When I run your code, the program crashes.


Yes, it segfaults. That was my point.


#include <iostream>
#include <string>

struct Stuff
{
int a;
double b;
};

void func(const Stuff& obj)
{
obj.a = 1;
}

int main()
{
Stuff s;
Stuff *sp = 0;

func(s);
// the next 3 produce comple time errors
func(0);
func(NULL);
func(sp);
// the next one is a stupid programmer error - deref'ing a NULL
// pointer. it crashes before func() is called - a good reason
// to use ref's exclusively rather than pointers.
func(*sp);

return 0;
}
The pros & cons of refs vs pointers could be argued forever.
Advocates of the different approaches will probably never
agree. So let's not beat it to death anymore.

Regards,
Larry
Jul 23 '05 #14

P: n/a
Stuart MacMartin wrote:
Why make every little routine test over and over again something that
isn't to ever happen?
Not sure what you mean here. If you can ensure that the error cannot
happen, then there's no point in testing for it. OTOH, if you can't be
sure it won't happen, then you either take your chances for the sake of
performance (and should ask yourself if it really is all that costly to
make the check), or you put in an error check.
The question people ask is, IMO, the wrong one.
People ask: When should I pass by reference?
The right question is "When should I pass by pointer?"

and the answer is "Whenever you want to allow a pointer-to-nothing
(i.e. 0)"
which is in my experience almost never.
That is certainly not a universal assumption. I would never intentionally
pass a null pointer unless I had explicit information telling me it was OK.
I go one step further:
Pass by const reference unless the object may change.
This way when you call some code the intent is crystal clear.

I don't buy the argument that someone might then dereference a null
pointer and thus you always have to protect your code. Your interface
is a contract. At least with references you are making your intent
clear.
Assuming the person maintaining the code actually looks at the function
declaration, rather than just the call. It would appear (much to my
amazement) many C++ programmers believe a programmer should *not* look at
the actual source code where the interface is declared.
Pass by pointer and you are saying "You're allowed to pass 0".
Too often if you rely on this in other people's code you'll be
surprised by seg faults because they did not handle being passed 0 --
they really meant it had to point to something.
It seems to me your understanding of the implication of a pointer parameter
is unfounded. The only time I might assume it's safe to pass a null
pointer is if the parameter has a default null value.
You rely on other things in the contract: that the kind of object is
the kind you ask for (no static_cast downcasting to the wrong type or
your program will crash), that the relationships between objects is set
up, and so forth. For clarity of code and ease of maintainability I've
found passing by reference (const and non-const) leads to far clearer,
more maintainable and more robust code.
I certainly prefer the use of operator[](), operator.() on a reference or an
object over doing the same on a pointer. If you are working with a
conceptual design that uses shared objects, you are almost certainly going
to use some kind of smart pointer. You will have to dereference that
somewhere. This is why I find the proposal to overload operator.() and
operator.*() so attractive. Of course some people believe the new move
semantics will obviate all need for such things. Clearly that is not the
case.

At least with a const reference, I *might* be able to catch an exception.
With a non-const reference, a null pointer is a segfault.
Adding null pointer checks all
over the place instead of only in the places where the pointers can be
0 hides programmer intent while adding noise to the program and slowing
runtime. So why do it?


Because code that does use pointers, and proper error checking won't crash
due to a null pointer, but code that uses references to pass variables
*can* crash because of a null pointer being passed to a reference. So far
as I know, there is no way to protect yourself from that, other than
checking for null before dereferencing.

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #15

P: n/a
Larry I Smith wrote:
Steven T. Hatton wrote:
John Carson wrote:
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:as********************@speakeasy.net
In your example, you are not trying to pass null, you are trying to
pass a literal.
He is passing NULL which is the same as 0.
'0', when it appears in your code, is a literal. If the reference were
const, the code /would/ compile.


In C++ NULL is zero (0).


Exactly my point. It is NOT a null pointer, it is a literal.
#include <iostream>
#include <string>

struct Stuff
{
int a;
double b;
};

void func(const Stuff& obj)
{
obj.a = 1;
}

int main()
{
Stuff s;
Stuff *sp = 0;

func(s);
// the next 3 produce comple time errors
func(0);
func(NULL);
func(sp);
The error on the last example is because you are passing a pointer to a non
pointer type, and has nothing to do with the value of the type. In the
pervious examples you are passing an integer literal which is likewise
illegal.

// the next one is a stupid programmer error - deref'ing a NULL
// pointer. it crashes before func() is called - a good reason
// to use ref's exclusively rather than pointers.
func(*sp);

return 0;
}
The pros & cons of refs vs pointers could be argued forever.
Advocates of the different approaches will probably never
agree. So let's not beat it to death anymore.

Regards,
Larry


--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #16

P: n/a
Steven T. Hatton wrote:
John Carson wrote:
Dereferencing a NULL pointer is undefined behaviour by section
8.3.2/4. When I run your code, the program crashes.


Yes, it segfaults. That was my point.


There's no mention of segfaulting in the standard. The behaviour is
undefined. That means that anything can happen, including the function
executing without any apparent problem.

DW
Jul 23 '05 #17

P: n/a
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ).
Not necessarily. Try passing a null pointer to ::strlen(). Just because a
pointer is passed doesn't necessarily mean that the function will permit it
to be null.
The code
becomes somewhat more self-documenting.
Yes, because you at least don't have to bother finding out if a null pointer
is acceptable.
Any comments on why this could be a bad idea or do you think it's just
a matter of taste?


One thing about the reference case is that you can't tell from the call
whether it is pass by value or pass by reference. In the pointer case it is
at least obvious from the call that an address is being passed, so you are
alerted that the function might change the object.

DW
Jul 23 '05 #18

P: n/a
Well I suppose most of this comes down to local convention. I prefer to
work with references, and allow a semantic difference between a
parameter passed by reference rather than passed by pointer.

Your comment:
Because code that does use pointers, and proper error checking won't
crash due to a null pointer, but code that uses references to pass
variables *can* crash because of a null pointer being passed to a
reference. So far as I know, there is no way to protect yourself from
that, other than checking for null before dereferencing.

And that's precisely the point.

I figure you should check for null before dereferencing (or otherwise
using what a pointer points to), and once you've safely dereferenced
continue to use that reference. You feel you should not trust your
caller, so insist on checking the pointer over and over again - and
instead of trusting your callers like I do, you trust the people who
write the routines you call. Since you'd check that the address of a
reference isn't 0, you see no semantic difference between passing a
pointer and a reference.

Just out of curiosity: do you do dynamic_cast of all your variables to
make sure the types are the same as the parameters you specified? This
might sound snide, but I've had people downcast or force a cast
incorrectly, with problems only showing up when the data model changes
significantly or subtly on on rare data. If you can't believe they are
passing a reference to an object when you ask for a reference, how can
you believe that they are passing the correct kind of object? It's
easy to fool the compiler into allowing this. The compiler can help
us, but only to a point. Eventually someone has to understand what a
routine is supposed to do before they call it.

Another thing that puzzles me in all of this: doesn't anyone use a
development environment? How can you not know the parameters and
whether they are passed by value or pointer or reference, const or
non-const?

Stuart

Jul 23 '05 #19

P: n/a
Well you CAN pass a reference to nothing though:

void f(int& i)
{
i ++;
}

int main()
{
int* i = new int;
int& ref = *i;
delete i;

f(ref); // tell me what does ref referencing to?
}

ben
Jul 23 '05 #20

P: n/a
Steven T. Hatton wrote:
[]
Most C++ books recommend references whenever possible, according to the
general perception that references are "safer and nicer" than pointers. In
contrast, at Trolltech, we tend to prefer pointers because they make the
user code more readable. Compare:

color.getHsv(&h, &s, &v);
color.getHsv(h, s, v);
Only the first line makes it clear that there's a high probability that h,
s, and v will be modified by the function call.


Hm. I think if the semantics is "return value" then it should be a
return value grammatically too - i.e. return some HSV struct or
similar. If there is some strong reason to pass in a pointer/ref
and store the return value there, then I tend to agree that it's
easier to read if it's a pointer.
However in this case the name "getHsv" makes it pretty clear too
what's going to happen...

And when it's const, I'd never use a pointer if I don't have to.
If the function needs an object and cannot deal with a null
pointer/ref, then why should it check for null? If the client
passes in some value by dereferencing a pointer, then it's clearly
the clients responsibility to assure that this pointer can never
be null...
I know that dealing with non-perfect but real-life programmers
isn't easy, but I think one has to draw a line somewhere. If
a programmer isn't able to understand the simple fact that he/she
can't dereference a null pointer then he/she really shouldn't be
a programmer.

And: how do your functions handle situations where the client
passes in a null pointer for something that may not be null?
assert, abort, throw (std::invalid_argument, ...?)?
Jul 23 '05 #21

P: n/a
David White wrote:
Steven T. Hatton wrote:
John Carson wrote:
Dereferencing a NULL pointer is undefined behaviour by section
8.3.2/4. When I run your code, the program crashes.


Yes, it segfaults. That was my point.


There's no mention of segfaulting in the standard. The behaviour is
undefined. That means that anything can happen, including the function
executing without any apparent problem.

DW


So what happens when you run it?

BTW, just as an aside, 'NULL' is the name of a #MACRO defined as '0'. A
pointer T* ptr; such that NULL == T; is an object of type 'pointer to T'.
'NULL' is, IMO, not appropriate for use as an adjective.

http://www.research.att.com/~bs/bs_faq2.html#null

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #22

P: n/a
Sheesh.

The caller could just as easily do:

int i;
int* pI = &i + 1;
f(i);

or

int* i = new int;
delete i;
f(i);

C++ gives you all sorts of ways of doing something bad, and there are
lots of bad pointers other than 0.

I claim passing by reference helps keep the noise level down and make
it clear where the valid pointer test should be made. Passing by
pointer muddies the water: whose responsibility is it?

Stuart

Jul 23 '05 #23

P: n/a
Steven T. Hatton wrote:
David White wrote:
Steven T. Hatton wrote:
John Carson wrote:

Dereferencing a NULL pointer is undefined behaviour by section
8.3.2/4. When I run your code, the program crashes.

Yes, it segfaults. That was my point.


There's no mention of segfaulting in the standard. The behaviour is
undefined. That means that anything can happen, including the
function executing without any apparent problem.

DW


So what happens when you run it?


It doesn't matter what happens when I run it. All that matters is what the
standard allows to happen, and that is anything at all. You can't assume
that because it segfaults on a particular platform using a particular
compiler that it will do so for every platform and compiler, or even that
the program that segfaulted for you will do so the next time you run it.
Some computers (e.g., Intel 8085, 8086) are not even capable of segfaulting.
Instead, they are likely to just grab the value at address 0 (or whatever
address is used as the null pointer) and happily execute the function.

DW
Jul 23 '05 #24

P: n/a
Ian wrote:
Kristo wrote:
Mr A wrote:
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

void func(Objec& object); //object must be an object
void func(Object* object); //object can be NULL


That looks like a very good idea to me, and IIRC, the FAQ agrees.
IMHO, it's more than a matter of style; it's also a matter of safety.
If a parameter should never be null, then don't give it the chance.

And passing by reference does this? I don't think so.


I do think so. Anyone else want to vote?

Jul 23 '05 #25

P: n/a
Stuart MacMartin wrote:
Well I suppose most of this comes down to local convention. I prefer to
work with references, and allow a semantic difference between a
parameter passed by reference rather than passed by pointer.
I suspect that could lead to problems if you apply that to code from outside
your local community. It would also seem wrong to criticize others who do
not share your conventional semantics.
Your comment:
Because code that does use pointers, and proper error checking won't
crash due to a null pointer, but code that uses references to pass
variables *can* crash because of a null pointer being passed to a
reference. So far as I know, there is no way to protect yourself from
that, other than checking for null before dereferencing.

And that's precisely the point.

I figure you should check for null before dereferencing (or otherwise
using what a pointer points to), and once you've safely dereferenced
continue to use that reference. You feel you should not trust your
caller, so insist on checking the pointer over and over again - and
instead of trusting your callers like I do, you trust the people who
write the routines you call.
Well, I have the advantage that I currently use only open source, so I can
verify, as well as trust. But, the fact of the matter is, I don't really
need to trust the function I call, other than to worry about subsequent
changes. If the function has a default null pointer parameter, I am pretty
safe passing a null pointer to it.
Since you'd check that the address of a
reference isn't 0, you see no semantic difference between passing a
pointer and a reference.
Actually, I can't check that the address of a reference is 0, but I can
assume it is non-zero in view of the fact that it makes no sense to have a
reference to '\0'.
Just out of curiosity: do you do dynamic_cast of all your variables to
make sure the types are the same as the parameters you specified? This
might sound snide, but I've had people downcast or force a cast
incorrectly, with problems only showing up when the data model changes
significantly or subtly on on rare data. If you can't believe they are
passing a reference to an object when you ask for a reference, how can
you believe that they are passing the correct kind of object?
Actually, there are some circumstances when the caller wouldn't really be
"wrong" to pass a parameter different than the one I handle.

virtual void operator()(osg::Node *node, osg::NodeVisitor* nv){
if(_doRefresh){
if(PAT_T* pat = dynamic_cast<PAT_T*>(node)){
_refresh(pat);
_doRefresh=false;
}
}
traverse(node,nv);
}

Note that the code above is rather standard for 3D animation where
performance is critical. But this is called once per traversal. OTOH, if
the if() condition is satisfied, the call to _refresh() will result in
thousands of operations. It's
easy to fool the compiler into allowing this. The compiler can help
us, but only to a point. Eventually someone has to understand what a
routine is supposed to do before they call it.

Another thing that puzzles me in all of this: doesn't anyone use a
development environment? How can you not know the parameters and
whether they are passed by value or pointer or reference, const or
non-const?


Well, I use Emacs and KDevelop. Typically the technique I use to know what
the function declaration looks like is called RTFS. Don't get me wrong, I
believe IDEs are very valuable. It's one of the greatest weaknesses of C++
that creating good IDEs is extremely difficult. There are several nice
ones for Java, and monodevelop seems to be shaping up nicely. I'm hoping
to figure out how to provide some additional features to KDevelop's C++
part.

Sadly, it would seem Borland is not going to be able to keep pace with their
primary competitor. This is mostly due to the fact that Borland doesn't
control the platform that holds 90% or more of the desktop OS market share,
while their competitor does.

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #26

P: n/a
Old Wolf wrote:
Ian wrote:
Kristo wrote:
Mr A wrote:

I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

void func(Objec& object); //object must be an object
void func(Object* object); //object can be NULL

That looks like a very good idea to me, and IIRC, the FAQ agrees.
IMHO, it's more than a matter of style; it's also a matter of safety.
If a parameter should never be null, then don't give it the chance.

And passing by reference does this? I don't think so.


I do think so. Anyone else want to vote?


Define parameter in this context.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #27

P: n/a
Steven T. Hatton wrote:
Larry I Smith wrote:
Steven T. Hatton wrote: [...]
AFAIK, you *can* pass a null to func() in your example, and the compiler
will accept it. Your code will segfault when you do so. If you pass a
pointer, you can check for null, before accessing it. I, therefore,
suggest using a pointer instead of a reference.

There is no such thing as a null reference. However, see below.
If a function takes a ref, then NULL can not be passed.
Attempting to pass NULL causes a compile error.

For example:
[snip] func(0); // causes a compile error
In your example, you are not trying to pass null, you are trying to pass a
literal. That results in the attempt to create a temporary object of type
int and assign it to the non-const reference.


True, 0 or NULL is the null pointer constant, which is not the same
thing as a null pointer.
This, however, will compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}


True, this will compile, and will result in undefined behavior.
However, the unbehavior is not in func for trying to use a "null
reference" (there being, again, no such thing) but in main for
dereferencing a null pointer.

"But," you may say, "main doesn't dereference the pointer. The
seg fault [or whatever] occurs in func!"

First, it is not unusual for a run-time error (if one occurs
at all) to happen some time after the undefined behavior that
caused it.

Second, people tend to mistakenly think that "deferencing" a
pointer means accessing the memory at the machine address stored
in the pointer. This is confusing a possible implementation of a
language concept with the concept itself. In C and C++, any time
you form an expression by applying the '*' operator to a pointer,
you have deferenced that pointer.

One might imagine it's a special case if the expression is used
to initialize a reference. After all, references and pointers are
both "just addresses" so "under the hood" you're not doing anything
at all. Again, this is confusing a possible implementation with the
language itself. In C++, if an expression dereferences a null
pointer, it is undefined behavior, regardless of how that
expression is then used.

In general, although it is nice to have some idea of what goes
on at the assembly code level, one cannot reductively understand
C++ in terms of machine code. To see how doing so might lead
one astray, consider an example which does not involve references:

int foo()
{
int n = 5;
int* p = &n;
return *p;
}

You don't have be a language lawyer to see that the expression *p
in this function dereferences the pointer p. Yet here, stripped
of comments, is the assembly listing for the above function
(from VC++ 7.1 with "optimize for size" specified):

?foo@@YAHXZ PROC NEAR
push 5
pop eax
ret 0
?foo@@YAHXZ ENDP

So what Steven's example shows is not that it is possible to
create a null reference, but rather that one must be careful
not to dereference a null pointer. That is certainly good
advice. :-)

Jul 23 '05 #28

P: n/a
Ian
Old Wolf wrote:
Ian wrote:
Kristo wrote:
Mr A wrote:
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

void func(Objec& object); //object must be an object
void func(Object* object); //object can be NULL

That looks like a very good idea to me, and IIRC, the FAQ agrees.
IMHO, it's more than a matter of style; it's also a matter of safety.
If a parameter should never be null, then don't give it the chance.


And passing by reference does this? I don't think so.

I do think so. Anyone else want to vote?

As has been show elsewhere on this thread, references can be null.

Ian
Jul 23 '05 #29

P: n/a
ni*****@microsoft.com wrote:
Steven T. Hatton wrote:
Larry I Smith wrote:
> Steven T. Hatton wrote: [...] >> AFAIK, you *can* pass a null to func() in your example, and the
>> compiler
>> will accept it. Your code will segfault when you do so. If you pass
>> a
>> pointer, you can check for null, before accessing it. I, therefore,
>> suggest using a pointer instead of a reference.
There is no such thing as a null reference. However, see below.
> If a function takes a ref, then NULL can not be passed.
> Attempting to pass NULL causes a compile error.
>
> For example:
> [snip] > func(0); // causes a compile error
In your example, you are not trying to pass null, you are trying to pass
a
literal. That results in the attempt to create a temporary object of
type int and assign it to the non-const reference.


True, 0 or NULL is the null pointer constant, which is not the same
thing as a null pointer.


Actually it is an integer literal which when assigned to a pointer to type T
is converted to a null pointer constant to T. The distinction may seem
trivial, but the error is not due to the fact that 0 is being used. It is
due to the fact that a literal is being used to initialize a temporary of
type int.
This, however, will compile:

#include <string>
std::string func(std::string& s) { return s; }
int main() {
std::string* s(0);
func(*s);
}


True, this will compile, and will result in undefined behavior.
However, the unbehavior is not in func for trying to use a "null
reference" (there being, again, no such thing) but in main for
dereferencing a null pointer.


The act resulting in the undefined behavior is in main where the attempt to
dereference a null pointer is made. Where the actual /behavior/ occurs is
a different story. Basically, accessing the null pointer gives
'permission' to produce undefined behavior.
"But," you may say, "main doesn't dereference the pointer. The
seg fault [or whatever] occurs in func!"

First, it is not unusual for a run-time error (if one occurs
at all) to happen some time after the undefined behavior that
caused it.
The segfault *is* the undefined behavior that results from the attempt to
dereference a null pointer.
Second, people tend to mistakenly think that "deferencing" a
pointer means accessing the memory at the machine address stored
in the pointer. This is confusing a possible implementation of a
language concept with the concept itself. In C and C++, any time
you form an expression by applying the '*' operator to a pointer,
you have deferenced that pointer.
The C++ Standard does not define what is meant by dereferencing a pointer.

5.3.1/1
"The unary * operator performs /indirection/: the expression to which it is
applied shall be a pointer to an object type, or a pointer to a function
type and the result is an lvalue referring to the object or function to
which the expression points. If the type of the expression is ?pointer to
T,? the type of the result is ?T.?"

An lvalue is said to refer to specific storage, so I would say that pretty
much means returning an address.
One might imagine it's a special case if the expression is used
to initialize a reference. After all, references and pointers are
both "just addresses" so "under the hood" you're not doing anything
at all. Again, this is confusing a possible implementation with the
language itself. In C++, if an expression dereferences a null
pointer, it is undefined behavior, regardless of how that
expression is then used.
No, applying the indirection operator to a variable of type pointer to type
T is the definition of a behavior. The _result_ is undefined.
In general, although it is nice to have some idea of what goes
on at the assembly code level, one cannot reductively understand
C++ in terms of machine code. To see how doing so might lead
one astray, consider an example which does not involve references:

int foo()
{
int n = 5;
int* p = &n;
return *p;
}

You don't have be a language lawyer to see that the expression *p
in this function dereferences the pointer p. Yet here, stripped
of comments, is the assembly listing for the above function
(from VC++ 7.1 with "optimize for size" specified):

?foo@@YAHXZ PROC NEAR
push 5
pop eax
ret 0
?foo@@YAHXZ ENDP
Well, yes, you can invoke the "as if" clause.
So what Steven's example shows is not that it is possible to
create a null reference, but rather that one must be careful
not to dereference a null pointer. That is certainly good
advice. :-)


For the record, I don't believe I actually said the result was a null
reference.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #30

P: n/a
Steven T. Hatton wrote:
Actually, there are some circumstances when the caller wouldn't really be
"wrong" to pass a parameter different than the one I handle.

virtual void operator()(osg::Node *node, osg::NodeVisitor* nv){
if(_doRefresh){
if(PAT_T* pat = dynamic_cast<PAT_T*>(node)){
_refresh(pat);
_doRefresh=false;
}
}
traverse(node,nv);
}


BTW, my reading of the Standard suggests there is no need to check that node
is not null before I try to dynamic_cast it. Does anybody disagree with
that understanding?
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #31

P: n/a

"Stuart MacMartin" <sj*@igs.net> wrote in message
news:11**********************@g43g2000cwa.googlegr oups.com...
Sheesh.

The caller could just as easily do:

int i;
int* pI = &i + 1;
f(i);
What wrong does the above line?

or

int* i = new int;
delete i;
f(i);
The above won't even compile.

C++ gives you all sorts of ways of doing something bad, and there are
lots of bad pointers other than 0.
Agree!

I claim passing by reference helps keep the noise level down and make
it clear where the valid pointer test should be made. Passing by
pointer muddies the water: whose responsibility is it?
Yes and no. It really depends on the semantics of the function. For example:
- If a referential parameter is needed for read operation only, I will
use const reference, or neither of both;
- If it is needed for write operation, then I will have it as a pointer,
so the user is aware of the write operation;
- In some cases where the write operation is conceptually trivial,
references are also preferred;
- If the function is to be used by C programs, then pointer is a must;

Stuart

Jul 23 '05 #32

P: n/a
"Ian" <no***@nowhere.com> wrote in message
news:11***************@drone2-svc-skyt.qsi.net.nz

As has been show elsewhere on this thread, references can be null.


No they can't. The C++ standard, section 8.3.2/4 says:

"a null reference cannot exist in a well-defined program, because the only
way to create such a reference would be to bind it to the "object" obtained
by dereferencing a null pointer, which causes undefined behavior."

Of course, nothing actually stops programmers from dereferencing null
pointers. The fundamental point here is that if you work with references all
(or almost all) the time, then you generally don't need to dereference
pointers, null or otherwise, and thus you avoid doing something that is
dangerous.

If the client code uses pointers, then it doesn't make a lot of difference
if the function accepts pointers or references; the pointer is going to have
to be dereferenced by either the client (if the function takes references)
or the function (if the function takes pointers). The gain is when *neither*
client *nor* function uses pointers.
--
John Carson

Jul 23 '05 #33

P: n/a
Steven T. Hatton wrote:
ni*****@microsoft.com wrote:

True, 0 or NULL is the null pointer constant, which is not the same
thing as a null pointer.


Actually it is an integer literal which when assigned to a pointer to type
T
is converted to a null pointer constant to T. The distinction may seem
trivial, but the error is not due to the fact that 0 is being used. It is
due to the fact that a literal is being used to initialize a temporary of
type int.


I said that wrong. A temporary of type int would be created and used to
initialize the non-const reference. That's what won't work. And for
obvious reasons.

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #34

P: n/a
"Steven T. Hatton" <ch********@germania.sup> wrote in
news:Yt********************@speakeasy.net:
Steven T. Hatton wrote:
Actually, there are some circumstances when the caller wouldn't
really be "wrong" to pass a parameter different than the one I
handle.

virtual void operator()(osg::Node *node, osg::NodeVisitor* nv){
if(_doRefresh){
if(PAT_T* pat = dynamic_cast<PAT_T*>(node)){
_refresh(pat);
_doRefresh=false;
}
}
traverse(node,nv);
}


BTW, my reading of the Standard suggests there is no need to check
that node is not null before I try to dynamic_cast it. Does anybody
disagree with that understanding?


Well... dynamic_casting a null pointer is defined. Section 5.2.7, clause
4.

Jul 23 '05 #35

P: n/a
"David White" <no@email.provided> wrote in message
news:KX********************@nasal.pacific.net.au
Mr A wrote:
Hi!
I've been thinking about passing parameteras using references instead
of pointers in order to emphasize that the parameter must be an
object.

Exemple:
void func(Objec& object); //object must be an object

instead of

void func(Object* object); //object can be NULL

I belive that this is a good idea since , in the reference case, it's
clear that NULL is not an option. It's also clear that NULL is an
option when a pointer is expected (stating the obvious :-) ).


Not necessarily. Try passing a null pointer to ::strlen(). Just
because a pointer is passed doesn't necessarily mean that the
function will permit it to be null.


Really? When I try this, the code compiles and the program crashes when run.
Of course, functions can check for null pointers (though this won't stop
compilation) but at least my copy of strlen apparently doesn't.
The code
becomes somewhat more self-documenting.


Yes, because you at least don't have to bother finding out if a null
pointer is acceptable.
Any comments on why this could be a bad idea or do you think it's
just a matter of taste?


One thing about the reference case is that you can't tell from the
call whether it is pass by value or pass by reference. In the pointer
case it is at least obvious from the call that an address is being
passed, so you are alerted that the function might change the object.

void fooptr(int * ptr);
void fooptr(const int * ptr);

vs

void fooref(int & ref);
void fooref(const int & ref);

int main()
{
int x;
fooptr(&x);
fooref(x);
}

What do you know from the fooptr(&x) call that you don't know from the
fooref(x) call or vice versa?

The only time you can know something from a function call is if you *never*
use references. In that case, when you pass by value you know that the value
won't be changed. If you pass by pointer, you still don't know either way.
The situation in which you never use references is of course when
programming in C. I think this preference for pointers is just a hangover
from C.

The real point is surely that when you call a function you are supposed to
know what it does. You figure out what you want done and you call a function
that is documented to do it. You don't call functions because the function
call "looks" like it will do what you want.

--
John Carson

Jul 23 '05 #36

P: n/a
"benben" <be******@hotmail.com> wrote in news:42d1c9f4$0$26951$afc38c87
@news.optusnet.com.au:
Well you CAN pass a reference to nothing though:

void f(int& i)
{
i ++;
}

int main()
{
int* i = new int;
int& ref = *i;
delete i;
You're setting yourself up for Undefined Behaviour. It's your
responsibility to ensure that the lifetime of the object that reference is
referring to is longer than the lifetime of the reference.
f(ref); // tell me what does ref referencing to?
Don't care... undefined behaviour.
}

ben


Jul 23 '05 #37

P: n/a
Ian <no***@nowhere.com> wrote in news:1121056041.542104@drone2-svc-
skyt.qsi.net.nz:
Old Wolf wrote:
Ian wrote:
Kristo wrote:

Mr A wrote:
>I've been thinking about passing parameteras using references instead
>of pointers in order to emphasize that the parameter must be an
>object.
>
>void func(Objec& object); //object must be an object
>void func(Object* object); //object can be NULL

That looks like a very good idea to me, and IIRC, the FAQ agrees.
IMHO, it's more than a matter of style; it's also a matter of safety.
If a parameter should never be null, then don't give it the chance.
And passing by reference does this? I don't think so.

I do think so. Anyone else want to vote?

As has been show elsewhere on this thread, references can be null.


Not "legally" (or to rephrase, not without invoking Undefined Behaviour
first).....
Jul 23 '05 #38

P: n/a
John Carson wrote:
"David White" <no@email.provided> wrote in message
Not necessarily. Try passing a null pointer to ::strlen(). Just
because a pointer is passed doesn't necessarily mean that the
function will permit it to be null.


Really? When I try this, the code compiles and the program crashes when
run. Of course, functions can check for null pointers (though this won't
stop compilation) but at least my copy of strlen apparently doesn't.


On my system it throws an exception.
The code
becomes somewhat more self-documenting.


Yes, because you at least don't have to bother finding out if a null
pointer is acceptable.
Any comments on why this could be a bad idea or do you think it's
just a matter of taste?


One thing about the reference case is that you can't tell from the
call whether it is pass by value or pass by reference. In the pointer
case it is at least obvious from the call that an address is being
passed, so you are alerted that the function might change the object.

void fooptr(int * ptr);
void fooptr(const int * ptr);

vs

void fooref(int & ref);
void fooref(const int & ref);

int main()
{
int x;
fooptr(&x);
fooref(x);
}

What do you know from the fooptr(&x) call that you don't know from the
fooref(x) call or vice versa?
in the case of fooptr() I can see that the address is being taken, and
therefor _know_ it is not passed by value. In the case of fooref(), I
can't tell if it's a pass by reference, or a pass by value.
The only time you can know something from a function call is if you
*never* use references. In that case, when you pass by value you know that
the value won't be changed. If you pass by pointer, you still don't know
either way.
I know it is not pass by value.
The situation in which you never use references is of course
when programming in C. I think this preference for pointers is just a
hangover from C.
The head guys at Trolltech have been programming in C++ since the late
1980s. I don't believe their recommendations are due to being stuck in C.
The real point is surely that when you call a function you are supposed to
know what it does. You figure out what you want done and you call a
function that is documented to do it. You don't call functions because the
function call "looks" like it will do what you want.


Well, you can read the documentation, or the source. Nonetheless, if you
can provide useful information at the call point with minimal cost, it
makes little sense not to do so. There are many times when a person
reading the code may not have read all the documentation, or all the
source. For example, if you are trying to debug someone else's code. It's
also the case that people forget things.

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #39

P: n/a
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:0Y********************@speakeasy.net
John Carson wrote:

void fooptr(int * ptr);
void fooptr(const int * ptr);

vs

void fooref(int & ref);
void fooref(const int & ref);

int main()
{
int x;
fooptr(&x);
fooref(x);
}
What do you know from the fooptr(&x) call that you don't know from
the fooref(x) call or vice versa?


in the case of fooptr() I can see that the address is being taken, and
therefor _know_ it is not passed by value. In the case of fooref(), I
can't tell if it's a pass by reference, or a pass by value.


The point is that you can't tell if the function changes x.
The real point is surely that when you call a function you are
supposed to know what it does. You figure out what you want done and
you call a function that is documented to do it. You don't call
functions because the function call "looks" like it will do what you
want.


Well, you can read the documentation, or the source. Nonetheless, if
you can provide useful information at the call point with minimal
cost, it makes little sense not to do so.


The cost is never using non-const references, which I consider to be a high
cost. It is actually a prohibitive cost, because it means you can't use
libraries that use non-const references. In the real world, we have to work
with other people's code and other people's decisions, which means that
self-documenting pass-by-value schemes can't work.
There are many times when
a person reading the code may not have read all the documentation, or
all the source. For example, if you are trying to debug someone
else's code. It's also the case that people forget things.


I find it rather extraordinary that a person could call a function without
knowing whether or not it changes values within the calling scope. It really
seems to me to be such a fundamental difference in function behaviour that a
programmer should know about it as a matter of course. In any event, if you
pass a pointer to any function, then you have to independently ascertain
whether values within the calling scope are changed even with C.

--
John Carson

Jul 23 '05 #40

P: n/a
Ian
John Carson wrote:
"Ian" <no***@nowhere.com> wrote in message
news:11***************@drone2-svc-skyt.qsi.net.nz

As has been show elsewhere on this thread, references can be null.

No they can't. The C++ standard, section 8.3.2/4 says:

"a null reference cannot exist in a well-defined program, because the
only way to create such a reference would be to bind it to the "object"
obtained by dereferencing a null pointer, which causes undefined behavior."

Of course, nothing actually stops programmers from dereferencing null
pointers. The fundamental point here is that if you work with references
all (or almost all) the time, then you generally don't need to
dereference pointers, null or otherwise, and thus you avoid doing
something that is dangerous.

Exactly. I was responding to the statement "If a
parameter should never be null, then don't give it the chance." -
implying that pass by reference is safe.

Passing *p where p == NULL can be worse than passing p as it's a rare
condition that is unlikely to be tested for. References give the
illusion of safety, not the reality.

I prefer to pass by reference, but have bee bitten more than once by
instances of dereferenced null pointers being passed.
If the client code uses pointers, then it doesn't make a lot of
difference if the function accepts pointers or references; the pointer
is going to have to be dereferenced by either the client (if the
function takes references) or the function (if the function takes
pointers). The gain is when *neither* client *nor* function uses pointers.

Which is why I prefer it. The risk of the occasional bad object is
outweighed by the syntactic convenience of pass by reference.

Ian

Jul 23 '05 #41

P: n/a
Ian
Steven T. Hatton wrote:
John Carson wrote:

"David White" <no@email.provided> wrote in message


Not necessarily. Try passing a null pointer to ::strlen(). Just
because a pointer is passed doesn't necessarily mean that the
function will permit it to be null.


Really? When I try this, the code compiles and the program crashes when
run. Of course, functions can check for null pointers (though this won't
stop compilation) but at least my copy of strlen apparently doesn't.

On my system it throws an exception.


A standard C library function throwing an exception??

Ian
Jul 23 '05 #42

P: n/a
John Carson wrote:
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:0Y********************@speakeasy.net
John Carson wrote:
fooptr(&x);
fooref(x);
What do you know from the fooptr(&x) call that you don't know from
the fooref(x) call or vice versa?
in the case of fooptr() I can see that the address is being taken, and
therefor _know_ it is not passed by value. In the case of fooref(), I
can't tell if it's a pass by reference, or a pass by value.


The point is that you can't tell if the function changes x.


That is correct. But if the API is consistent in its use of pointers to
indicate potential modification of parameters, you can be confident that
there are no modifications happening to non-pointer parameters.
Well, you can read the documentation, or the source. Nonetheless, if
you can provide useful information at the call point with minimal
cost, it makes little sense not to do so.


The cost is never using non-const references, which I consider to be a
high cost.


Never? That's taking things to extremes. I've already stated that
std::ostream& and the like should not be excluded. I really haven't had
that much of a chance to play with Qt4 to find out how they are handling
such situations.
It is actually a prohibitive cost, because it means you can't
use libraries that use non-const references.
No. It only means that you don't do it in *your* libraries. It's just
silly to say you would never use other people's libraries because they
don't conform you your coding conventions. Unfortunately established
practices in C++ are very heterogeneous, and excluding libraries on the
basis of failing to follow some established convention would probably
exclude 90% of all C++ code _regardless_ of the convention used as a
filter.

In the real world, we have to
work with other people's code and other people's decisions, which means
that self-documenting pass-by-value schemes can't work.
Nonsense. That's equivalent to saying coding conventions are useless
because not everyone uses the same ones.
There are many times when
a person reading the code may not have read all the documentation, or
all the source. For example, if you are trying to debug someone
else's code. It's also the case that people forget things.


I find it rather extraordinary that a person could call a function without
knowing whether or not it changes values within the calling scope. It
really seems to me to be such a fundamental difference in function
behaviour that a programmer should know about it as a matter of course.


How can you know about what the function does the first time you see the
code? Have you ever tried to troubleshoot code in a high priority
situation in a language you have never worked in, while talking on the
phone to the semi-technical person in Korea describing the problem they are
seeing on their end? The more useful information you can glean from subtle
artifacts in the code, the more maintainable it is.
In
any event, if you pass a pointer to any function, then you have to
independently ascertain whether values within the calling scope are
changed even with C.


I'm not sure what you mean here. How is this any different with references?
The fact of the matter is, when it comes to working with shared objects as
part of the conceptual design of a system, it is simply easier to pass
pointers. Unfortunately, until we have overloaded operator.(), we have to
deal with some less than elegant consequences.

--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #43

P: n/a
Ian wrote:
Steven T. Hatton wrote:
John Carson wrote:

"David White" <no@email.provided> wrote in message


Not necessarily. Try passing a null pointer to ::strlen(). Just
because a pointer is passed doesn't necessarily mean that the
function will permit it to be null.

Really? When I try this, the code compiles and the program crashes when
run. Of course, functions can check for null pointers (though this won't
stop compilation) but at least my copy of strlen apparently doesn't.

On my system it throws an exception.


A standard C library function throwing an exception??

Ian


I was talking about the code I posted. Not specifically strlen which I
haven't used in a decade.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #44

P: n/a
Ian wrote:
Passing *p where p == NULL can be worse than passing p as it's a rare
condition that is unlikely to be tested for. References give the
illusion of safety, not the reality.
If you're the library writer, that's not something you should worry
about. He who dereferences a pointer is responsible for making sure
it's not null.
I prefer to pass by reference, but have bee bitten more than once by
instances of dereferenced null pointers being passed.


Then I suggest you tell your users to stop invoking UB.

Kristo
Jul 23 '05 #45

P: n/a
Kristo wrote:
Ian wrote:
Passing *p where p == NULL can be worse than passing p as it's a rare
condition that is unlikely to be tested for. References give the
illusion of safety, not the reality.


If you're the library writer, that's not something you should worry
about. He who dereferences a pointer is responsible for making sure
it's not null.
I prefer to pass by reference, but have bee bitten more than once by
instances of dereferenced null pointers being passed.


Then I suggest you tell your users to stop invoking UB.

Kristo


Notice that this code is basically immune to null pointer problems (assuming
nv is handleded similarly):

virtual void operator()(osg::Node *node, osg::NodeVisitor* nv){
if(_doRefresh){
if(PAT_T* pat = dynamic_cast<PAT_T*>(node)){
_refresh(pat);
_doRefresh=false;
}
}
traverse(node,nv);
}

There may be some circumstances when a null pointer is exactly what you want
to pass to your function. For example, if I don't need nv, it could be set
to null by the caller. It's actually very common to do that when working
with composites.
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
Jul 23 '05 #46

P: n/a
> As has been show elsewhere on this thread, references can be null.

....and pointers can point to garbage, even to the point that
dereferencing crashes.
And MyObject* p passes as a parameter might actually point to
YourObject.

The point of this whole discussion seems to be whether it's way too
easy
to pass a dereferenced null pointer to a parameter that is defined as
reference.
This is an error in the caller - but is it the responsibility of the
called function
to catch this error?

Stuart

Jul 23 '05 #47

P: n/a
(Wish I knew how to properly quote text in google groups.
Our ISP's newsgroup handling is currently broken)

You say:
I suspect that could lead to problems if you apply that to code from outside
your local community. It would also seem wrong to criticize others who do
not share your conventional semantics.
I suspect this particular one is not a problem.
If I ask for a reference, I don't think there's any ambiguity that I
might be allowing *(MyType*)0;

You say: If the function has a default null pointer parameter, I am pretty
safe passing a null pointer to it.
You mentioned this before, and I didn't comment but I agree that's a
clear signal. But it does seem to me a bit restrictive to insist that
the default parameter be 0 to be sure it allows 0. Much clearer IMO to
use references and pointers to distinguish this.

You say: Well, I use Emacs and KDevelop


Ah yes. I forgot that there have only ever been two very good
development environments, and I've been spoiled. One was Apollo's, and
the other (no flame wars please) Microsoft's. Much as there are bugs
and scalability issues in Microsoft's development environment, I'm used
to good information about what I'm calling and what I'm expected to do
as caller.

Stuart

Jul 23 '05 #48

P: n/a
You say:
BTW, my reading of the Standard suggests there is no need to check that
node
is not null before I try to dynamic_cast it. Does anybody disagree
with
that understanding?

My reply:
Yes, dynamic_cast will return 0 if passed 0.
But if this code is time-critical, don't do this from MFC.
dynamic_cast is a performance bottleneck.
It works by doing a whole pile of string compares.
(This is why our objects have virtual IsSpecificType methods that we
can invoke.)

Stuart

Jul 23 '05 #49

P: n/a
"Steven T. Hatton" <ch********@germania.sup> wrote in message
news:yI********************@speakeasy.net
It is actually a prohibitive cost, because it means you can't
use libraries that use non-const references.
No. It only means that you don't do it in *your* libraries. It's
just silly to say you would never use other people's libraries
because they don't conform you your coding conventions.
Unfortunately established practices in C++ are very heterogeneous,
and excluding libraries on the basis of failing to follow some
established convention would probably exclude 90% of all C++ code
_regardless_ of the convention used as a filter.


It is not silly at all. The point is that you want a cheap indicator of what
a function does. Just look at the function call and you know. Well, if that
is the sort of cursory study that is involved, how do you know if the
function is one of "yours" or one from some other library? Plainly you can't
know, so your cheap indicator is as likely to mislead as inform. Sensible
programmers will ignore it.

As for your extrapolation of my statement to all coding practices, the value
of most coding conventions is independent of whether other code is following
them. Take declaring function parameters const when a function doesn't
change them. That protects the coder of the function from inadvertently
changing a value. This coding practice has value for that individual
function even if no other function in the entire program follows it. That is
not the case with your recommended use of pointers because the information
content of the practice is critically dependent on how widely used it is.
How can you know about what the function does the first time you see
the code? Have you ever tried to troubleshoot code in a high priority
situation in a language you have never worked in, while talking on the
phone to the semi-technical person in Korea describing the problem
they are seeing on their end? The more useful information you can
glean from subtle artifacts in the code, the more maintainable it is.
Now we have descended into absurdity.
In any event, if you pass a pointer to any function, then you have to
independently ascertain whether values within the calling scope are
changed even with C.


I'm not sure what you mean here. How is this any different with
references?


It isn't. That is my point. Even in C, your coding convention has limited
value because most of the time you need to look at the documentation/source
code to see what a function does. In C++, it has next to no value.
The fact of the matter is, when it comes to working with
shared objects as part of the conceptual design of a system, it is
simply easier to pass pointers.


An assertion for which I have heard no good arguments.

--
John Carson

Jul 23 '05 #50

110 Replies

This discussion thread is closed

Replies have been disabled for this discussion.