views:

110

answers:

5

Dereferencing pointers can make the code very hard to read. What I usually do is putting a reference to the pointed object and working with the reference. Example:

shared_ptr<std::vector<int> > sp = get_sp_to_vector();
std::vector<int>& vec = *sp;
...
vec.push_back(5);

I wonder if it's a good practice. Does it have any drawback?

Update: To complete the example, I'd define get_sp_to_vector() the following way:

shared_ptr<std::vector<int> >  get_sp_to_vector()
{
    // create a vector and send back a shared pointer pointing at it
    shared_ptr<std::vector<int> >  sp(new std::vector<int>);
    sp->push_back(1);  sp->push_back(3);
    return sp;
}
+2  A: 

I wouldn't consider this a good practice. Pointers are a main-stay of C/C++ development and b/c of that, C/C++ coders are comfortable with the de-reference syntax needed by pointers. I do try and avoid the use of pointers when possible (not for syntactical reasons though), but sometimes it's just the best tool for the job. If you have code that is gnarly b/c you're using a pointer, I would typically de-reference it into a function that passes the object by reference which essentially does what you're doing, but in my opinion it does so in a more elegant way. So instead of:

shared_ptr<std::vector<int> > sp = get_sp_to_vector();
std::vector<int>& vec = *sp;
...ugly stuff...
vec.push_back(5);

I would do:

void func(std::vector<int> &vec)
{
     ... previously ugly stuff...
     vec.push_back(5);
}

shared_ptr<std::vector<int> > sp = get_sp_to_vector();
func(*sp);

EDIT:
This isn't to say that you should create a function simply to create nicer syntax for pointers, as it is to state that if you don't like pointer syntax and your code uses clean and concise functions, you can simply make the functions take references and de-reference your pointer when calling the function. For situations where you have only a few calls to *p or p->x, it seems silly to create a function with a reference or to create a reference in order to call p.x. Just use the pointer syntax in these cases as this is C/C++ syntax.

Others have brought up using references within loops where a pointer may have to be de-referenced many times. I do agree that in these cases a reference would be beneficial.

RC
@RC: You are doing exactly the same thing... simply hiding it in a function call (which is appropriate depending on what operations are going to be done).
ceretullis
Yes, which I stated in my answer. I find passing a dereferenced pointer to a function as a reference vs creating a reference within the same code block different. I'm not saying I would write a function to simply make the code look different syntactically. My point being that if you don't like pointers, don't pass them to function calls as pointers.
RC
@RC: okay... +1, I buy that, but this isn't clear in your answer. It appears, and maybe I'm just dense, that you are suggesting Jabba do an extract-method type refactoring just to hide the creation of the reference.
ceretullis
+2  A: 

Using local references is common, especially inside loop bodies, but there is one requirement: only do it when the reference will obviously live as long as the target object.

This usually isn't hard to guarantee, but here are some bad examples:

shared_ptr<X> p = get_p();
X& r = *p;
p.reset(); // might result in destroying r
use(r); // oops

// or:
shared_ptr<X> p = get_p();
X& r = *p;
p = get_some_other_p(); // might result in destroying r
use(r); // oops
Roger Pate
shared_ptr doesn't have a release() function, just reset(), but I agree with this - having two variables coupled together adds a non-zero overhead in complexity. Since one of them is a reference, you can't even update r to match the new value of p.
Steve Jessop
Whoops, thanks, as you recognized the intention is what's important.
Roger Pate
+2  A: 

IMHO, I think this is an acceptable practice (with some caveats - See Roger Pate's post). If you're adding a line of code just for the push_back() call, then I don't think that is acceptable.

However, if you find you are dereferencing the pointer many times, then not only is dereferencing it once into a reference object acceptable, it could be a performance win (depending on your compiler, the code in question, the phases of the moon, etc).

ceretullis
+1 for mentioning a good use where a pointer is de-referenced often. I wonder how often compilers may do this optimization for you when it detects loops with pointers being de-referenced? Seems like it would need/want to know how many times the loop would be executed in order to know whether or not it is beneficial.
RC
Actually, dereferencing a pointer into a reference does nothing for performance in pretty much every compiler. Under the hood, references are basically implemented the same way pointers are.
Terry Mahaffey
Agreed with Terry Mahaffey. However, using references to specific entries in an array might save repeated additions.
rlbond
@"Terry Mahaffey": I agree. References are implemented exactly the same as pointers under the hood, and if you use the reference a *few times* there is no possible performance gain. I've also found on occasion where a pointer to a struct caused the compiler to dereference the pointer on access to each member... and that by dereferencing the pointer once into a reference and using the reference I was able to improve the compiler emitted assembly. Does that sound reasonable to you?
ceretullis
+1  A: 

If I am actually doing pointer manipulation, then I leave it a pointer. If my pointer is simply a nilable reference, then I leave it a pointer. If I am assured or wanting to assure that the pointer will always be non-zero (I.e. if I am are returning the non-nil object from a method) then I make this explicit by using a reference.

Roger Nelson
+1  A: 

Working back from your proposed code, I don't agree that:

shared_ptr<std::vector<int> > sp = get_sp_to_vector();
...
sp->push_back(5);

is "very hard to read". It's also shorter than your code. So although I don't think there's much wrong with defining and using a local reference, I also don't think you should make a rule to always do so.

Perhaps if your pointer code is very hard to read, it's because you're missing some trick which would make it simpler. Maybe if you ask another question with an example of bad pointer code that you'd currently fix with a reference, SOers would find alternative fixes.

Steve Jessop