views:

996

answers:

6

I recall reading somewhere that using references to smart pointers can cause memory corruption. Is this simply because of using the reference of the smart pointer after its been destroyed? Or does the reference counting get messed up?

Thanks for clarifying

+5  A: 

Assuming you are talking about shared_ptr here...

Is this simply because of using the reference of the smart pointer after its been destroyed?

This is a good answer. You may not know absolutely the lifetime of the pointer your reference refers too.

To get around this, you'd want to look into boost::weak_ptr. It doesn't participate in reference counting. When you need to use it, it gives you a shared_ptr which goes away once your done with it. It will also let you know when the refered to pointer has been collected.

From the weak_ptr documentation

The weak_ptr class template stores a "weak reference" to an object that's already managed by a shared_ptr. To access the object, a weak_ptr can be converted to a shared_ptr using the shared_ptr constructor or the member function lock. When the last shared_ptr to the object goes away and the object is deleted, the attempt to obtain a shared_ptr from the weak_ptr instances that refer to the deleted object will fail: the constructor will throw an exception of type boost::bad_weak_ptr, and weak_ptr::lock will return an empty shared_ptr.

Note the method expired() will also tell you if your ptr is still around.

Doug T.
+2  A: 

When using smart pointers (or any allocation management object) you are counting on the behaviors defined in the constructor/destructor to manage refs/derefs/locks/unlocks. As a result, those types of objects must be true objects to perform properly. when using references to such objects (or pointers) you are bypassing the mechanism (and asking for a wedgie).

Dan Hewett
+1  A: 

There are still many cases in which a reference to a smart pointer is a good idea. An obvious example is the assignment method of the smart pointer class itself, which accept a reference to another smart pointer as its parameter.

Making a method that accepts a smart pointer reference means that the parameter doesn't increment the smart pointer's internal reference count. This can improve performance - but probably not a lot. Also, there are a lot of things the method cannot do with the reference - or the original smart pointer. If you know what these things are and avoid them, passing by reference works just fine. Of course, the purpose of smart pointers is to avoid having to know these things.

Also, if you have a method that will modify the value of a smart pointer parameter, passing as a reference is required, as it is with any other type.

Jeff B
+1  A: 

The "smart" part of smart pointers is managed by the constructors, destructors, assigment operators, and other functions of the smart pointer class. By using a reference, you are circumventing these operations -- the constructor will not get called when your reference is initialized, and the destructor will not get called when your reference goes out of scope.

In essence, a reference to a smart pointer is a dumb pointer, with all the risks and gotchas that the latter entails.

JohnMcG
+9  A: 

The bad thing to do is not "passing" the reference to smart pointer, it's "storing" the reference to smart pointer.

IOW,

foo(smart_ptr &ptr)

is ok. The object that the pointer refers to will exist as long as the caller of foo has not exited, at the least. That makes manipulation of ptr inside foo safe.

On the other hand,

class Bar {
    Bar(smart_ptr &p) ptr_(p){}
private:
    smart_ptr &ptr_;
}

is extremely bad idea. Bar instance now has a reference to the object ptr_ is pointing at, but it did not increment the ref count. Memory corruption is imminent.

Arkadiy
A: 

We have custom made smartpointers and we always make a habit of passing a 'const refsomething &'

it doesn't increment or decrement the smart pointer, and as such - and more importantly - calls to InterLockedIncrement/Decrement are avoided which in turns avoids a memory fence and all the things that go with that : bus locking, cache invalidation, ...

QBziZ