Question about QSharedPointer



  • Hi,

    I use QSharedPointer as a smart pointer class, which is very convenient.

    Now I have a situation in which a class has to call a function and pass a pointer to itself. Normally I would just pass a "this" pointer to the object, but I cannot just pass QSharedPointer<myclass>(this) since the Doc states in the QSharedPointer-constructor: "Creates a QSharedPointer that points to ptr. The pointer ptr becomes managed by this QSharedPointer and must not be passed to another QSharedPointer object or deleted outside this object."

    Is there a way around this problem?
    Of course, one possibility would be to let every object have a copy of the QSharedPointer, that holds that object, but that clearly wouldn't be very nice.

    Also a general question: Why does QSharedObject allow several instances of one pointer at all? Wouldn't it be better to keep track of all the pointers in one place (static), so when there is a new QSharedPointer constructed by calling the constructor and passing the pointer, it simply adds to the static reference counter and notifies the other instances? Or is there a class that does that already?

    Thanks a lot,
    D.


  • Moderators

    QSharedPointer is for memory management. It is used for pointers where the user would have to handle the cleanup of the memory allocation. So you do not have to keep track of your memory allocations and delete those memory when no longer needed.
    If you use it for a *this pointer it will not work.

    QSharedPointer is as all smart pointers convenient, but not the cure of everything. You need to use them wisely.



  • Hey,
    thanks for your reply!

    What you wrote is, of course, right...
    But when I have a situation in which it generally makes sense to use QSharedPointer, and still want to pass a this pointer, that obviously doesn't work. My question was, why this is the way it is or if there is an alternative for such a case.

    If not, it wouldn't be much hassle to write a class by myself, which basicly works like QSharedPointer and can handle multiple instances, but I was wondering if there was a reason why QSharedPointer doesn't support that.
    Although I can't think of a good reason, it might be (and is quite proabable) that I'm just missing something to understand why it should be a bad idea to have multiple instances of a shared pointer. So maybe someone knows more about that?

    Thanks!
    D.


  • Moderators

    I am definitely not the best to explain it in all detail.

    Typically with QSharedPointer you assign only memory which have allocated with new. As every smart pointer it is keeping track of the number of references to this memory. It basically uses a counter. The counter is increased when a new reference is created and it is decreased when the destructor is called. In addition in the destructor delete will be called to free the memory when no more references are existing.

    *this is a hidden pointer which you may use when you require within a method access to the object itself. However, it is just a pointer, but it is not defined how the memory has been allocated. You might have created the object using new or you may just declared it. Theoretically you could place the this pointer in a QSharedPointer, but imagine what happens when the destrcutor would actually delete your object. When you pass the this pointer to some objects handling within your object this would result in a catastroph. Also in other case it would be a similar problem. Eventually it would try to delete an object which has been destroyed already.

    If the object would not have been created with new, the delete would have a problem again. It tries to delete non allocated memory.



  • Hi
    thanks for your kind reply :)

    [quote author="koahnig" date="1329419865"]I am definitely not the best to explain it in all detail.
    Typically with QSharedPointer you assign only memory which have allocated with new. As every smart pointer it is keeping track of the number of references to this memory. It basically uses a counter. The counter is increased when a new reference is created and it is decreased when the destructor is called. In addition in the destructor delete will be called to free the memory when no more references are existing. [/quote] I know how reference counter based smart pointers work, but my problem lies somewhere else...

    [quote author="koahnig" date="1329419865"]*this is a hidden pointer which you may use when you require within a method access to the object itself. However, it is just a pointer, but it is not defined how the memory has been allocated. You might have created the object using new or you may just declared it. Theoretically you could place the this pointer in a QSharedPointer, but imagine what happens when the destrcutor would actually delete your object. When you pass the this pointer to some objects handling within your object this would result in a catastroph. Also in other case it would be a similar problem. Eventually it would try to delete an object which has been destroyed already.
    If the object would not have been created with new, the delete would have a problem again. It tries to delete non allocated memory.[/quote] I get your point, which is a very valid one. But that can't be an explanation for my question, since you can produce the same error by just writing something like
    @MyClassName A; QSharedPointer<MyClassName> myPointer(&A);@

    No need for the "this" pointer.

    The problem that you are describing is, as far as I can see, a general "problem" of smart pointers, but that problem remains no matter if your smart pointer class is able to handle multiple instances or not.

    But so far I don't see any disadvantage of a shared pointer class that can handle "multiple instances". Since of a pointer there basically can only be one instance (nothing else makes sense), why allow the user to create several instances that interfere with each other and not make all the instances use the same static reference counting?
    What are the reasons for that?

    In other words:
    @MyClassName A; QSharedPointer<MyClassName> p1(&A); QSharedPointer<MyClassName> p2(&A);@
    This would lead to problems eventually, since every QSharedPointer keeps it's own reference counting. But why does QSharedPointer do it that way?
    It came to my mind that if you would implement my idea, you would have to have some kind of static map, that maps from the pointers to the reference counting which might be a performance issue.
    But then at least you could store a static map like that and give the user a static function to get the QSharedPointer for a pointer while keeping everything else the same. So only in cases where the user needs to look if there already exists an instance of a shared pointer of a certain object, he uses this static function. No performance lost.

    Thanks,
    D.


  • Moderators

    [quote author="Donner" date="1329422570"]
    @MyClassName A; QSharedPointer<MyClassName> myPointer(&A);@

    @MyClassName A; QSharedPointer<MyClassName> p1(&A); QSharedPointer<MyClassName> p2(&A);@
    [/quote]
    Both examples will crash when the first destructor is called.

    Test this small example:
    @
    #include <QSharedPointer>
    class CTest
    {
    int INum;
    public:
    CTest()
    : INum ( 0 )
    {
    }
    int get () const
    {
    return INum;
    }
    void set( int i )
    {
    INum = i;
    }
    };
    int main(int argc, char *argv[])
    {
    CTest tst;
    QSharedPointer < CTest > sptr ( & tst );
    sptr->set ( 2 );
    return 0;
    }@
    You can run it up to the return, but then you get a crash. At least with msvc 2005.

    [quote author="Donner" date="1329422570"]
    No need for the "this" pointer.
    [/quote]
    You leave one part open. How do you get your smart pointer into your object?
    You have created an object and you created a pointer to that object which has been stored in a smart pointer. Even if it would not crash you need a mechanism to get it into the object. But is certainly doable somehow.

    [quote author="Donner" date="1329422570"]
    But why does QSharedPointer do it that way?
    It came to my mind that if you would implement my idea, you would have to have some kind of static map, that maps from the pointers to the reference counting which might be a performance issue.
    But then at least you could store a static map like that and give the user a static function to get the QSharedPointer for a pointer while keeping everything else the same. So only in cases where the user needs to look if there already exists an instance of a shared pointer of a certain object, he uses this static function. No performance lost.
    [/quote]
    Well this is not a QSharedPointer but the general definition of smart pointers.
    The next part is probably against the general definition of OOP and of C++.
    I do not know if it would be possible to define a programming language in such a way. That is for sure far outside of my experience. So I have nothing really to reply ;-)



  • [quote author="koahnig" date="1329424224"]
    Both examples will crash when the first destructor is called.
    ...
    You can run it up to the return, but then you get a crash. At least with msvc 2005.[/quote]
    I know! That is why I brought these examples up in the first place ;)

    [quote author="koahnig" date="1329424224"]You leave one part open. How do you get your smart pointer into your object? [/quote]
    THAT is the original question I asked! That is my problem ;)

    [quote author="koahnig" date="1329424224"]You have created an object and you created a pointer to that object which has been stored in a smart pointer. Even if it would not crash you need a mechanism to get it into the object. [/quote]
    Exactly, that was what I was saying. And now I'm just wondering why the constructor of QSharedPointer doesn't act like such a mechanism, thus it would check if the given pointer is already stored in a shared pointer and if so it would create a copy of that shared pointer and all would be well ;)

    [quote author="koahnig" date="1329424224"]Well this is not a QSharedPointer but the general definition of smart pointers.
    The next part is probably against the general definition of OOP and of C++.
    I do not know if it would be possible to define a programming language in such a way. That is for sure far outside of my experience. So I have nothing really to reply ;-) [/quote]
    Well, I don't see a problem with it's possibility as I described how it could be done (static map)... Though you are probably right that it wouldn't be perfect OOP style, but I'm wondering if there are other reasons besides that ;)



  • [quote author="Donner" date="1329428519"]
    [quote author="koahnig" date="1329424224"]You have created an object and you created a pointer to that object which has been stored in a smart pointer. Even if it would not crash you need a mechanism to get it into the object. [/quote]
    Exactly, that was what I was saying. And now I'm just wondering why the constructor of QSharedPointer doesn't act like such a mechanism, thus it would check if the given pointer is already stored in a shared pointer and if [/quote]

    I know no smart pointer implementation, that uses global maps to do such stuff. If you need the smart pointer inside the object to give it to other sub classes, you cann add that by a method that copies it. Bute then the class holds itself (will never be deleted).

    That's how smart pointers work. There are several types of smart pointers:

    memory watching with ref counting (like shared pointer)

    scoped smart pointer (std::auto_ptr)

    or even some , that just check, whether the reference object exists (QPointer)

    None of these uses global maps (as this would be a massive problem with multiple threads).



  • [quote author="Donner" date="1329414917"]If not, it wouldn't be much hassle to write a class by myself, which basicly works like QSharedPointer and can handle multiple instances, but I was wondering if there was a reason why QSharedPointer doesn't support that.
    Although I can't think of a good reason, it might be (and is quite proabable) that I'm just missing something to understand why it should be a bad idea to have multiple instances of a shared pointer. So maybe someone knows more about that?
    [/quote]
    Might I recommend you don't try to implement your own version? Implementing good shared pointers is hard. Yes, the basic principles are not that hard to grasp, but the devil is in the details. I would recommend you study the book Modern C++ Design by Andrei Alexandrescu. It has a very insightful chapter on smart pointers.



  • I was having the same issue, and came up with this solution:

    Let your object derive from QSharedData, and replace the QSharedPointer's with QExplicitlySharedDataPointer.

    The reference count is now kept inside the object, not managed by the pointers.
    You can create a new QExplicitlySharedDataPointer from your 'this' pointer now.

    I have not tested this solution, but I'm going to rewrite my own code now and find out if I am correct :-)



  • I have the same problem with QSharedPointers but soon realized that I was doing this wrong.

    I have the following situation:
    There is a Provider object that handles all communication between my program and a remote server. It has a List object which contains several Type objects and is given to other objects. The list is an abstraction to hide the Provider object, meaning I want to use the List object to add/edit/remove the Type objects.
    Because the Type objects are given to various other objects that are interested (ListViews for example), it is needed to use a QSharedPointer to check if it is being used and if the Type object is still valid.

    When the Type object itself is changed, it will call a function of the List object which calls a function of the Provider object which will send an command to the server. My first thought was to use a QSharedPointer in the 'changed' functions but realized it would be better to send a plain pointer and let the 'changed' functions determine the QSharedPointer attached to the object. (This was possible because the List object actually creates the Type objects by using new). This way, you don't create a new QSharedPointer to the same object nor do you need a global map but you do use some kind of map functionality by looking up your QSharedPointer.

    In short:
    When you want to pass the 'this' pointer as a QSharedPointer, you first pass it on as a plain pointer and then determine the QSharedPointer used to create the object. If this is not possible in your situation, I think you have to change your program or reconsider if using QSharedPointers is the correct way.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.