QSharedPointer, how to pass them around, and do I need them?

chikuba picture chikuba · Mar 23, 2012 · Viewed 16.1k times · Source

Been trying to understand shared pointer for a few days now and it feels like I cant seem to get it. Not sure if it's just to obvious or if it's too complicated. First of all, could anyone please give me an example where you would ACTUALLY use shared pointers. The examples on Wikipedia makes no sense to me. And how would you pass a shared pointer to another function or create an object with a shared pointer. So, how do you pass it around and where would you use it? ANY information or examples would be great.

Also, I have this issue where I don't know what to use. I have this function where I allocate a QFile and passes it to a function in another class. That function takes the file as a QIODevice* and then creates an object containing the file. I was wondering what the best solution would be here and how (if I should) use a shared pointer here? How can I make a shared pointer with <QFile> and pass it in where the function takes <QIODevice>. Feels like I don't get shared pointers at all...

My other approach would be to put the allocation of the QFile in a QScopedPointer. I then pass it to the class and when creating the object where the file will be stored, I use QPointer or QScopedPointer. In the end of the first calling function I should call take() right?

function () {
   QScopedPointer<QFile> item(new QFile("filename"));
   SomeClassObject->doStuff(item.data());
   item.take();
}
---------------------------------
SomeClass::doStuff(QIODevice *item) {
    _currentObject = new MyObject(item); // should _currentObject be a smartpointer?
    ...
}
---------------------------------
class MyObject {
    QPointer<QIODevice> _item;

    ...
    MyObject(QIODevice *item) {  _item = item; }
}

So I want a way to store pointers and a way to handle them during creation if "new" throws an exception.

Answer

Attila picture Attila · Mar 23, 2012

The point of shared pointers (and other similar wrappers for pointers) is to handle destruction of the pointer-to object properly. That is instead of having to manually make sure you delete the last copy (and only the last copy), the shared pointer takes care of it for you when it goes out of scope. The shared part means that you can create copies of this wrapper object (the shared pointer object) and it will "share" the pointer-to object between the copies (just as if you made a copy of a regular pointer) with the added benefit described above.

As for your code, SomeClass::doStuff() should have a QScopedPointer<QFile> parameter (instead of a QIODevice* one) as you are passing item to it, which has that type.

Same with MyObject's constructor: have it take a parameter of QPointer<QIODevice> or QSharedPointer<QIODevice> type. In general, everywhere where you would use pointers, use QSharedPointer instead (with the appropriate template type). This will save you from headaches related to accessing deleted objects later on.

Of course, sometimes you actually need the raw QIODevice pointer (e.g. for third-party library call), then you would use the data() member function of the shared pointer object. Just make sure you do not persist (that is store or otherwise copy beyond what's necessary) the returned raw pointer, because that will undercut the purpose of the shared pointers -- the shared pointers will not know about your extra raw pointer that is not under the management of the shared pointer objects.

EDIT: take() releases the ownership of the pointed-to object from a scoped pointer, so when the scoped pointer is destroyed, it does not delete the object. You would ant ot use it in a situation when you transfered ownership to somthing else -- like in your case to MyObject.