views:

555

answers:

4

References in C++ are a conveneint construct that allow us to simplify the following C code:

f(object *p){
  //do something
}

int main(){
  object* p = (object*) calloc(sizeof(object));
  f(p);
}

to

f(object& o){
  //do something
}

int main(){
  object o = object();
  f(o);
}

Shared pointers are another convenience in C++ that simplify memory management. However, I am not sure how to pass a shared_ptr to a function like f(object& o) which accepts arguments by reference?

f(object& o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(*p);
}

Will the shared pointer be incremented when its object is passed by reference to a function?

+2  A: 

Will the shared pointer be incremented when its object is passed by reference to a function?

No, as you are accessing the raw pointer and then passing it. You want to do something similar to this:

f(shared_ptr<object> o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(p);
}
Yacoby
+4  A: 

Take a shared_ptr by value, and the reference count will increase. This is easier when you typedef it:

typedef boost:shared_ptr<object> object_ptr;

void foo(object_ptr obj)
{
    obj->/* stuff*/;
    obj.reset(); //only resets this local copy, that means:
                 // reduce reference count (back to 1), and
                 // set obj to point at null.
}

int main(void)
{
    object_ptr obj(new object());
    foo(obj);
}

Keep in mind references are aliases. When you pass by reference, you're not passing pointers, copies, etc..., you're aliasing another object. (In reality they are implemented as pointers):

typedef boost:shared_ptr<object> object_ptr;

void foo(object_ptr& obj)
{
    obj.reset(); // the references was never increased, since a copy has not
                 // been made, this *is* obj in main. so the reference 
                 // goes to 0, and obj is deleted
}

int main(void)
{
    object_ptr obj(new object);
    foo(obj); // after this, obj has been reset!
}

Always remember to be const correct, to prevent errors:

typedef boost:shared_ptr<object> object_ptr;

void foo(const object_ptr& obj)
{
    obj.reset(); // cannot do! 
}

int main(void)
{
    object_ptr obj(new object);
    foo(obj);
}

I think you should prefer to pass smart pointers as references when possible, to avoid extraneous increments and decrements (and copies and whatnot).

GMan
... and avoid passing smart pointers as arguments at all if the function doesn't actually need a smart pointer (i.e. it doesn't make a copy for later use).
Pavel Minaev
A: 

First things first, from a functionality point of view, references in C++ are exactly the same as pointers. They only reason they were added to the language was to make the syntax of operator overloading be more natural. (For example to allow one to write a+b instead of &a+&b)

Your C and C++ code samples are absolutely not equivalent. The C version of your C++ code would be:

f(object *p){
  //do something
}

int main(){
  object o;
  object_constructor(&o);
  f(&o);
  object_destructor(&o);
}

In fact, this is the kind of code that your C++ compiler will conceptually generate.

With regards to your second question: Yes, that is the correct way to call the function f. The shared pointer counter will not be incremented. The actual pointer to the object will be passed, as if you were not using a shared_ptr. It is safe however, as long as f isn't doing anything funky. Just remember that the same thing exactly is happening as if f's parameter took a pointer instead of a reference. The only difference is that the compiler automagically passes the address of the variable without you having to explicitly use the & operator.

I personally do not like to ever pass variables by reference(passing by const reference is ok though). I prefer to use a pointer instead since it makes it clearer at the call site that the function that we are calling may potentially modify it's argument(since the & symbol is visible at the call site).

Peace

bartsimpson
Sorry, but "references in C++ are exactly the same as pointers" is wrong. Also, maybe it's just style but I think most C++ programmers will agree passing pointers instead of references is silly. Now you have to check for null all the time. References are more natural.
GMan
A: 
f(object& o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(*p);
}

Will the shared pointer be incremented when its object is passed by reference to a function?

In the code above - no. p will have its reference counter equal to 1 at all times. You can verify this in a debugger. shared_ptr's reference counter counts the number of shared_ptr instances that point to the same object, it doesn't track references you create by calling operator* (). And it doesn't have to - since p is guaranteed to live until the end of the scope and the function call is in this same scope (or deeper) p will be there during the entire call to f(). So everything is OK.

... unless in f you take the address of o and store somewhere that will last after f returns. This you should avoid by all means - pass the shared_ptr if you need to do that.

sbk