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

pass by reference vs. pointer passing

0 views
Skip to first unread message

blix

unread,
Oct 27, 2000, 11:50:41 PM10/27/00
to
I'm trying to use C++ instead of C but am running into some difficulties
understanding things. Is there really a functional difference between:

void MyFunc(CMyClass* p)
{
p->DoSomething(...)
}
and
void MyFunc(CMyClass& p)
{
p.DoSomething(...)
}

I am also trying to understand the differences between returning a pointer
and returning a reference. Likes this:

CMyClass* GetMyClass() { return pMyClass; }
CMyClass* pMyClass = GetMyClass();
pMyClass->DoSomething(...)

Seems simple and easy to understand. There is only 1 instance of CMyClass in
memory and you just pass around it's pointer. However, with the reference
stuff like this:

CMyClass& GetMyClass() { return MyClass; }
CMyClass MyClass = GetMyClass();
MyClass.DoSomething(...)

Doesn't this cause the copy constructor for CMyClass to be called, therefore
now having two instantiations of the class in memory? And extra cpu cycles
are wasted in performing the copy constructor?

I am trying to grasp why passing references around instead of pointers is
better. Can someone please give me a little education?

And one more thing... when using STL is it better to put the actual object
in a container like this:
vector<CMyClass> MyClassVector;
MyClassVector vec;
vec.push_back(CMyClass(...)); // this seems wasteful cause it forces a
call to the copy constructor

Or a pointer to the object:
vector<CMyClass*> MyClassVector;
MyClassVector vec;
vec.push_back(new MyClass(...)); // seems better to me

Can someone explain why C++ is advantageous in this regard?

Thank you in advance,
Steve

Jon Bell

unread,
Oct 28, 2000, 12:51:38 AM10/28/00
to
In article <l2sK5.77670$1_.13...@news1.rdc1.az.home.com>,

blix <steve....@home.com> wrote:
>I'm trying to use C++ instead of C but am running into some difficulties
>understanding things. Is there really a functional difference between:
>
>void MyFunc(CMyClass* p)
>{
> p->DoSomething(...)
>}
>and
>void MyFunc(CMyClass& p)
>{
> p.DoSomething(...)
>}

I can think of two, offhand.

1. With pointers, you have to beware that they might be NULL. References,
on the other hand, must be initialized with an object of the appropriate
type, so you can basically count on them being valid. It *is* possible
for a devious programmer to create what amounts to a null reference, but
you have to bend over backwards to do it.

2. You can "reseat" pointers, but not references. In your first example,
your function can make p point to a different object, but in your second
example, your function cannot make p refer to a different object.

--
Jon Bell <jtb...@presby.edu> Presbyterian College
Dept. of Physics and Computer Science Clinton, South Carolina USA
[ Questions about newsgroups? Visit http://www.geocities.com/nnqweb/ ]
[ or ask in news:news.newusers.questions ]

blix

unread,
Oct 28, 2000, 1:52:04 AM10/28/00
to
I would think that is an advantage to using pointers... that you can
'reseat' them. Or cast to them anything you want. Very flexible. I want to
use C++ but it just seems everytime I try it just eats up so much memory or
cpu usage that is totally unnecessary.

blix

"Jon Bell" <jtb...@presby.edu> wrote in message
news:G34Iu...@presby.edu...

Josh Sebastian

unread,
Oct 28, 2000, 2:54:26 AM10/28/00
to
On Sat, 28 Oct 2000 03:50:41 GMT, "blix" <steve....@home.com>
wrote:

>I'm trying to use C++ instead of C but am running into some difficulties
>understanding things. Is there really a functional difference between:
>
>void MyFunc(CMyClass* p)
>{
> p->DoSomething(...)
>}
>and
>void MyFunc(CMyClass& p)
>{
> p.DoSomething(...)
>}

Is there a *functional* difference? Other than the possibility of a
null pointer in the first one, no. Pass by reference versus pass by
indirection is more of a religious (stylistic) argument than a
technical one. References were introduced primarily to support
operator overloading, where pass by indirection just doesn't make any
sense.

>I am also trying to understand the differences between returning a pointer
>and returning a reference. Likes this:
>
>CMyClass* GetMyClass() { return pMyClass; }
>CMyClass* pMyClass = GetMyClass();
>pMyClass->DoSomething(...)
>
>Seems simple and easy to understand. There is only 1 instance of CMyClass in
>memory and you just pass around it's pointer. However, with the reference
>stuff like this:
>
>CMyClass& GetMyClass() { return MyClass; }
>CMyClass MyClass = GetMyClass();
>MyClass.DoSomething(...)
>
>Doesn't this cause the copy constructor for CMyClass to be called,
>therefore now having two instantiations of the class in memory? And extra cpu cycles
>are wasted in performing the copy constructor?

Maybe. If it can be optimized away, it will. The difference is that
the semantics are different. In the first example, you are making
using the object whose address was returned by the function. In the
second, you are using a *copy* of the object returned by the function.
There is *no* functional difference (again, with the exception of a
null pointer) between the first (pointer) version and this:

CMyClass& MyClass = GetMyClass();

>I am trying to grasp why passing references around instead of pointers is
>better. Can someone please give me a little education?

- References can't be NULL, so you can save your valuable CPU cycles
by not having to check to make sure.
- It is rather difficult (but possible!) to make an invalid reference.
- You can and must count on a reference being valid.
- There is no speed difference.
- References need not be dereferenced.
- const references can be bound to temporaries (this one's important)

>And one more thing... when using STL is it better to put the actual object
>in a container like this:
>vector<CMyClass> MyClassVector;
>MyClassVector vec;
>vec.push_back(CMyClass(...)); // this seems wasteful cause it forces a
>call to the copy constructor
>
>Or a pointer to the object:
>vector<CMyClass*> MyClassVector;
>MyClassVector vec;
>vec.push_back(new MyClass(...)); // seems better to me
>
>Can someone explain why C++ is advantageous in this regard?

You can do either one. Who said the second version isn't C++?

Both call the same ctor for object creation.
No ctor is called for argument passing (vector::push_back takes a
const reference).
One ctor *might* (depending on how clever your compiler is) be called
for the non-pointer version when the object is placed in the vector (I
think it won't if optimizations are turned up).
With the pointer version, you must dereference the pointer to get to
the object (not a free operation).
With the pointer version, you must remember to delete the object (not
a free operation).
With the pointer version, you cannot use the default predicates for
the STL functions like find, sort, accumulate, etc.


Remember, just because a copy *can* be made doesn't mean it *will* be
made. Do you have to be careful? Yes. Do you have to be paranoid? No.
_______

"Yields falsehood when preceded by its quotation" yields falsehood when preceded by its quotation.

Josh Sebastian
<cur...@earthlink.net>

Kent Dahl

unread,
Oct 28, 2000, 3:47:55 AM10/28/00
to
Josh Sebastian wrote:
> - const references can be bound to temporaries (this one's important)

This sounds like a hole in my C++ knowledge. Care to elaborate?

--
<[ Kent Dahl ]>================<[ http://www.stud.ntnu.no/~kentda/ ]>
)____(stud.techn.;ind.øk.data)||(softwareDeveloper.at(Trustix))_(
/"Opinions expressed are mine and not those of my Employer, "\
( "the University, my girlfriend, stray cats, banana fruitflies, " )
\"nor the frontal lobe of my left cerebral hemisphere. "/

blix

unread,
Oct 28, 2000, 3:47:05 AM10/28/00
to
Thanks, very helpful post. The item where you say, "const references can be
bound to temporaries (this one's important)"... I didn't quite understand
that. Why is it important? What do you mean bound to temporaries?

The reason I am asking all this is because today I tried using the reference
operator all over the place. I have an STL map that maps an unsigned long to
my object. I was just having the most difficult time understanding when,
why, and how my copy constructor was being called and when the operator= was
being called. Seemed like a real battle because I don't understand it real
well. So I removed all the reference stuff and just used plain old pointers
(something I fully understand) and all is well. But I don't want to give up
on C++ that easy.

Maybe I didn't understand the copy constructor too well. And also I can't
figure out the operator< overload. Do you define it as a member function of
the class? Is this how it would work?

CMyClass
{
public:
CMyClass() : m_nNum(1) {}
CMyClass(int num) : m_nNum(num) {}

// not too sure about this either what if you have a lot of member
functions?
CMyClass(const CMyClass& MyClass)
{ m_nNum = MyClass.m_nNum; }
// will this work just as well? not sure if it is even compilable, haven't
tried
CMyClass(const CMyClass& MyClass)
{ memcpy(this, &MyClass); }

// really not sure about operator< if this isn't right can you explain?
bool operator<(const CMyClass& a, const CMyClass& b)
{ return a.m_nNum < b.m_nNum; }
private:
int m_nNum;
};

CMyClass MyClass1(100);
CMyClass MyClass2 = MyClass1; // copy construct and 2nd constructor
called??

blix


"Josh Sebastian" <cur...@earthlink.net> wrote in message
news:p1skvs065ve7bdu0s...@4ax.com...

Josh Sebastian

unread,
Oct 28, 2000, 4:26:59 AM10/28/00
to
On Sat, 28 Oct 2000 07:47:05 GMT, "blix" <steve....@home.com>
wrote:

>Thanks, very helpful post. The item where you say, "const references can be
>bound to temporaries (this one's important)"... I didn't quite understand
>that. Why is it important? What do you mean bound to temporaries?

A temporary is an object that has no name. Literals, for example, are
temporaries. So:

void foo(int const&);

foo(3); // OK. Pass by (const) reference

void f(BigClass const&);
foo(BigClass()); // OK. Pass by (const) reference

Also, consider this:
void foo(ArithmeticClass const&);
ArithmeticClass a1=3, a2=4;
foo(a1 + a2);

You simply cannot do an equivalent thing with pointers because you
can't take the address of a temporary (well, you can, but it will be
invalid before you get a chance to do anything useful). Temporaries
bound to const references, OTOH, are guaranteed to not be destroyed
until after the reference is gone.

>The reason I am asking all this is because today I tried using the reference
>operator all over the place. I have an STL map that maps an unsigned long to
>my object. I was just having the most difficult time understanding when,
>why, and how my copy constructor was being called and when the operator= was
>being called. Seemed like a real battle because I don't understand it real
>well. So I removed all the reference stuff and just used plain old pointers
>(something I fully understand) and all is well. But I don't want to give up
>on C++ that easy.

Go slow. Don't try to learn it all at once. Use *simple* classes that
do nothing except help you learn. I find this class (and variations on
it) to be extremely useful:
class Count
{
public:
Count() : id(n++) { std::cout << id << " default ctor" <<
std::endl; }
Count(Count const&) : id(n++) { std::cout << id << " copy
ctor" << std::endl; }

int num() const { return id; }

private:
static int n;
int id;
};

It gives every object of type Count a unique "serial number" so you
can tell when an object was copied and when the copy was optimized
away. You could add an operator= as well.

>Maybe I didn't understand the copy constructor too well. And also I can't
>figure out the operator< overload. Do you define it as a member function of
>the class? Is this how it would work?

Operators are addressed near the bottom.

>CMyClass
>{
>public:
> CMyClass() : m_nNum(1) {}
> CMyClass(int num) : m_nNum(num) {}
>
> // not too sure about this either what if you have a lot of member
>functions?
> CMyClass(const CMyClass& MyClass)
> { m_nNum = MyClass.m_nNum; }

Better:
CMyClass(CMyClass const& MyClass) : m_nNum(MyClass.m_nNum) { }

> // will this work just as well? not sure if it is even compilable, haven't
>tried
> CMyClass(const CMyClass& MyClass)
> { memcpy(this, &MyClass); }

No. Never do that. It will screw up polymorphism. That probably won't
make a difference in a little class like this, but when you start
making class hierarchies and virtual functions, it will cause horrible
bugs. Plus, memcpy is not considered "good style" in C++ for most
tasks. It is often looked down upon as a "C hack" :) (But that's
because there are better ways to do similar things in C++)

The copy ctor, copy assignment operator, and dtor are special
functions. They automatically get defined for your class if you don't
define them yourself. By default, the copy ctor jsut copies over all
the member objects (similar to a struct in C). The default copy
assignment operator just assigns each of the member objects (again,
similar to a struct in C). The default dtor just calls the dtor for
all the member objects.

There is a "Rule of Three" that says that if you need to define a
special version of any one of those three functions, you need to
define them all. That's true 99% of the time.

> // really not sure about operator< if this isn't right can you explain?
> bool operator<(const CMyClass& a, const CMyClass& b)
> { return a.m_nNum < b.m_nNum; }
> private:
> int m_nNum;
>};

Operators can be members or non-members. Member operators take one
less parameter than non-members because the implicit this parameter
takes the place of the first one. I prefer to make my operators
non-members (with the exception of operator= which *must* be a member)
but that is just style.

// member version:
class C
{
// ...
bool operator<(C const& c) const;
// ...
};

// non-member version
class C
{
// ...
};
bool operator<(C const& c1, C const& c2);

Often, non-member operators are made to be friends of the class.

>CMyClass MyClass1(100);
>CMyClass MyClass2 = MyClass1; // copy construct and 2nd constructor
>called??

Yes. For a given type T,
T t(x);
is the same as
T t = x;

But that's the only place where = resolves to a ctor call. If you had
done this:
T t;
t = x;
You would get a ctor (default ctor for t) call *and* an assignment
operator call.

Play around with (an expanded version of) that Count class and see
what behavior you get.

blix

unread,
Oct 28, 2000, 5:20:24 AM10/28/00
to

"Josh Sebastian" <cur...@earthlink.net> wrote in message
news:el1lvscf4cb4vjmol...@4ax.com...

> On Sat, 28 Oct 2000 07:47:05 GMT, "blix" <steve....@home.com>
> wrote:
I see. I tried the Count class. But the linker complained about 'static int
n'. It specifically said:
count.obj : error LNK2001: unresolved external symbol "private: static int
Count::n" (?n@Count@@0HA)
Debug/count.exe : fatal error LNK1120: 1 unresolved externals
I'm using MSVC6.0.

So I made 'static int n' a global variable and it works.

I saw the following:
Count c1; // 0 default ctor
Count c2(c1); // 1 copy ctor
Count c3 = c1; // 2 copy ctor
Count c4; // 3 default ctor
c4 = c2; // nothing, but would probably see operator= right?

So I tried to implement operator equal:

Count& operator=(Count const& c)
{ std::cout << id << " operator=" << std::endl; id = c.id; return
*this; }

This seems to produce the correct results. But am not sure if this is the
right way to do it. Is this right? You have to physically copy each data
member and return a dereference to this?

Josh Sebastian

unread,
Oct 28, 2000, 5:39:47 AM10/28/00
to
On Sat, 28 Oct 2000 09:20:24 GMT, "blix" <steve....@home.com>
wrote:

>
>"Josh Sebastian" <cur...@earthlink.net> wrote in message
>news:el1lvscf4cb4vjmol...@4ax.com...
>> On Sat, 28 Oct 2000 07:47:05 GMT, "blix" <steve....@home.com>
>> wrote:
>I see. I tried the Count class. But the linker complained about 'static int
>n'.

Sorry, last line didn't copy over (operator error :) Just after the
class definition, put this:

int Count::n = 0;

IMO, it's stupid, but you gotta do it.

>So I made 'static int n' a global variable and it works.

Sure. That'll work too.

>I saw the following:
>Count c1; // 0 default ctor
>Count c2(c1); // 1 copy ctor
>Count c3 = c1; // 2 copy ctor
>Count c4; // 3 default ctor
>c4 = c2; // nothing, but would probably see operator= right?

Right.

>So I tried to implement operator equal:
>
> Count& operator=(Count const& c)
> { std::cout << id << " operator=" << std::endl; id = c.id; return
>*this; }
>
>This seems to produce the correct results. But am not sure if this is the
>right way to do it. Is this right?

It looks OK to me. I wouldn't copy over the id number, though. I would
leave the id of both objects alone and just do something like:
std::cout << id << " assigned from " << c.id << std::endl;
or something like that. But neither version is "right". They do
different things.

>You have to physically copy each data
>member and return a dereference to this?

If all you do is assign the corresponding members, then you don't need
an assignment operator at all (the default one does that). You only
need to make your own assignment operator if you want to do something
different (such as perform output, like Count does).

You also might want to add output for the destructor. Then you can see
when and in what order your objects are being destroyed.

Jon Bell

unread,
Oct 28, 2000, 8:00:23 AM10/28/00
to
In article <8QtK5.77690$1_.13...@news1.rdc1.az.home.com>,

blix <steve....@home.com> wrote:
>I would think that is an advantage to using pointers... that you can
>'reseat' them. Or cast to them anything you want. Very flexible.

Sure, when you *need* the flexibility. But lots of times you don't, and
having that extra unneeded flexibility can sometimes cause things to coil
up under your feet and trip you up. It's a matter of choosing a tool that
just fits the job at hand.

After all, "goto" statements are a lot more flexible than "if/else" or
"while" or "for" statements, but most programmers nowadays don't use them
very often.

Robert C. Paulsen, Jr.

unread,
Oct 28, 2000, 8:17:52 AM10/28/00
to

Consider the following example:
====================================================================
#include <iostream>

void funcA(const int& x) { // const ref
std::cout << x << std::endl; // function doesn't change argument
}

void funcB(int& x) { // non-const ref
std::cout << x << std::endl; // function doesn't change argument
}

void funcC(int& x) { // non-const ref
x=7; // function changes argument
}

int get_int() {
return 42;
}

int main() {
funcA(42);
funcA(get_int());
}
====================================================================
In main, try changing the function calls to funcB or funcC and see
what errors (or warnings) you get. funcB may seem like a small
change from funcA, but the compiler needs to treat calls to the two
differently since funcB's signature allows it to behave like funcC,
which is likely not what you want when used as in main.

--
____________________________________________________________________
Robert Paulsen pau...@texas.net

Jukka Liimatta

unread,
Oct 28, 2000, 6:04:05 PM10/28/00
to
> 'reseat' them. Or cast to them anything you want. Very flexible. I want to
> use C++ but it just seems everytime I try it just eats up so much memory
or
> cpu usage that is totally unnecessary.

You either don't know C++ wery well to write efficient code with it, or the
compiler you are using is substandard quality. C++ programmer can write
_very_ high performance software. ;-)


Jukka


0 new messages