Sign in to follow this  
johand_

passing by reference versus passing by pointer

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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. ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this