passing by reference versus passing by pointer

Started by
7 comments, last by Zahlman 14 years, 10 months ago
Ok this is something that's bothering me a little. Usually, when I have an object that needs to store a reference to another object I do something like this:

class A
{
public:
	A(B& b) : m_B(&b)
	{
	}
	
	const B& GetB() const
	{
		return *m_B;
	}
private:
	B* m_B;
}; 

Here A is an object that needs a B to exist, hence the passing by reference. Having to pass a B by reference instead of by pointer ensures that it cannot be null. A won't be the new owner of the B object, if it would I would have passed it as an auto_ptr to indicate that ownership is being transfered. A also isn't a shared owner of B, otherwise I would have passed a shared pointer to B. Someone once told me I should just pass a pointer to B in this case, and add an assert (to do the not is null check) since it would make it a little bit more clear that it might be stored within the A object and that if you pass an object by reference you would expect that it is only used within that function. If I apply my rules to Direct3D it would mean that I would have to pass objects like ID3D10Buffer as reference. I tried google with search phrases like ID3D10Buffer& and DIRECT3DVERTEXBUFFER9&, but both returned zero zero hits. That's when I started to wondering if I might be doing something wrong. What do you guys think?
Advertisement
You do know you can store a reference instead of a pointer, right?

class A{public:   A(B& b) : m_B(b) { }   const B& GetB() const   { return m_B; }private:   B& m_B;};



Aside from that... I say pass references whenever you can. Using a pointer and checking for NULL is a bit silly IMO, since you can have a free compile-time guarantee that the parameter is non-NULL if you pass by reference.

As for working with APIs like DirectX, I'd say just go with whatever convention the API designers seem to want: i.e. in this case you'd work with pointers to your DirectX interfaces rather than references.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:
You do know you can store a reference instead of a pointer, right?


Yes I know. The problem with storing references is that it prevents a default assignment operator from being generated, which means that in order for your object to be copyable you'll have to implement it yourself. What do you recommend in this case, storing a pointer or suppling an assignment operator?

Quote:
As for working with APIs like DirectX, I'd say just go with whatever convention the API designers seem to want: i.e. in this case you'd work with pointers to your DirectX interfaces rather than references.


That seems like good advice. Thanks. It will make things a little bit inconsistent, but i guess as long as I treat all the d3d objects the same (using pointers) it won't be a problem and it makes things a bit easier to use.
Quote:Original post by johand_
Yes I know. The problem with storing references is that it prevents a default assignment operator from being generated, which means that in order for your object to be copyable you'll have to implement it yourself. What do you recommend in this case, storing a pointer or suppling an assignment operator?


IMHO the best approach is to use references and just write your own copy constructor/assignment operator. Most nontrivial classes should be following the Rule of Three anyways, so this shouldn't translate into that much additional code.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by ApochPiQ
IMHO the best approach is to use references and just write your own copy constructor/assignment operator.

And what is the copy assignment operator supposed to do with the reference?
Quote:
Using a pointer and checking for NULL is a bit silly IMO, since you can have a free compile-time guarantee that the parameter is non-NULL if you pass by reference.


If I'm not mistaken, there is no such compile-time guarantee. If you have pointers that can be NULL, you'll need to check them somewhere. References can also become dangling references. So, references can give you somewhat a false sense of security.

If the class just uses a pointer and is not the owner, I believe boost::weak_ptr expresses that idea. A simple pointer can be OK too, but you just have to be sure that the pointed object won't be deallocated elsewhere during the lifetime of the object.
Personally, I always use smart pointers ( either counted/shared or not ) when I want one object to keep a reference to another one, like A.m_b in your example. I usually only use references when I want to pass an object/struct to a function for a one-off purpose.

The reason for my preference is mostly syntactical rather than functional (I think even Stroustrup said that references in C++ are little more than syntactic sugar...). When I'm calling a function like my_object.move_to( new_pos ), I don't like having to write &new_pos just to avoid it being passed by value. By passing it as a const ref in this case, I can treat it like it was passed by value, and avoid having the visible traits one has when dealing with a pointer (&, * and ->).

More importantly though, if I have something like collision_manager.add_collidable_entity( entity ), I'll always prefer to pass entity as a (smart) pointer, because that way I know it's going to be referenced outside the scope of that function. Also, if one is using smart pointers, you can maintain the same functionality as a normal pointer and have "automatic" null checks upon every access to it - this way all error-checking is inside the smart pointer class and you don't need to clutter your code with asserts outside it.
Quote:Original post by DevFred
Quote:Original post by ApochPiQ
IMHO the best approach is to use references and just write your own copy constructor/assignment operator.

And what is the copy assignment operator supposed to do with the reference?



Bleh, good point. I need to stop posting when I'm sleep deprived [lol]

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by ApochPiQ
Quote:Original post by DevFred
Quote:Original post by ApochPiQ
IMHO the best approach is to use references and just write your own copy constructor/assignment operator.

And what is the copy assignment operator supposed to do with the reference?



Bleh, good point. I need to stop posting when I'm sleep deprived [lol]


There's a reason I do things the way the OP originally proposed. ;)

This topic is closed to new replies.

Advertisement