1

I have shared_ptr variable in my class object (ObjA). There is a requirement where this object is to be stored as (void*) entity of another Class' object (ObjB).

My question is, what will be the behaviour of shared_ptr (will associated heap memory be freed?, what will happen to its reference count?)-

  1. when ObjA is converted to void*

  2. when void* entity of ObjB is cast back to (ClassA *)

Simplified Code:

Class AA{

    shared_ptr<int> aptr;

    public:
        AA(){
            aptr = make_shared<int>(100);
        }
        shared_ptr<int> get_aptr(){
            return aptr;
        }
};


Class BB{

    void *smpl;

    public:

        void setter(void* p){
            smpl = p;
        }

        void* getter(){
            return smpl;
        }
};

int main(){

    AA *objA = new AA();
    BB *objB = new BB();

    objB->setter(objA);
    //status of allocated int in class AA here?

    //some code later
    AA *objA_2 = (AA*)objB->getter();
    //status of allocated int in class AA here?

    shared_ptr<int> p2 = objA_2->get_aptr();
    //is this allowed

}

My prime concern is- how to deallocate the memory of shared_ptr. (Given it is enclosed in void* object, which can not be deleted- shared_ptr remains in scope at all times) I tried to delete objB, with appropriate casting to its component void* in destructor-

BB::~BB(){
    delete (*AA)smpl;
}

but this is giving error as shared_ptr variable in class AA does not allows explicit delete- it frees its allocated area only when it goes out of scope. (In this case, it never knows when it goes out of scope!)

Also, class BB is a third party class- I cant modify the type void* of smpl member variable (_userData variable in Node class, in Cocos2dx). Please help to resolve this memory leak..

Apporve
  • 13
  • 3
  • The lifetime of the shared ptr ignores the void state: if the source ptr dies, the resource is deallocated. If you make a second shared ptr to the same resource (not through shared ptr copy ctor), they will both think they own the resource, and double deletion (bad) will result. – Yakk - Adam Nevraumont May 29 '15 at 11:00
  • Besides, [this answer](http://stackoverflow.com/a/573345/2412846) tells you most about the cast-part. – davidhigh May 29 '15 at 11:01
  • @Yakk- are you saying that two shared_ptr's point to same location without increasing ref_count. Not sure if thats possible. – Apporve Jun 01 '15 at 09:36
  • @ davidhigh- thanks for the link, got to learn about usability of static_cast when working with void*. Though not yet sure that would answer my current issue.. – Apporve Jun 01 '15 at 09:38
  • @Apporve: the cast is unrelated to the pointer stuff. But it's good to know when working with `void *` and such, isn't it ;-) – davidhigh Jun 01 '15 at 09:50
  • @Apporve: see the edit in my answer, which should answer your questions. – davidhigh Jun 01 '15 at 10:00

1 Answers1

0

The void * here acts an observing pointer. It does not affect the shared pointer at all, because the shared pointer doesn't know the raw pointer to its contained object even exists.

That would be different if you choose a shared_ptr<void> instead of the raw pointer (and construct it through the original shared pointer, i.e. your setter should be replaced by void setter(std::shared_ptr<void> const& p) for example).

In this case, the reference count is affected and the living of the pointed-to object would be ensured. With regard to this option, see here.


EDIT: From your comment, it seems as if you're looking for a setup similarly to the following:

struct AA
{
    //...
};


struct BB
{
    std::shared_ptr<void> smpl;

    void setter(std::shared_ptr<void> const& p)
    {
        smpl = p;  //now the ref count of your shared_tr to AA is increased
    }
};

int main()
{    
    auto objA = std::make_shared<AA>();
    auto objB = std::make_shared<BB>();

    objB->setter(objA);

    std::cout<<objA.use_count()<<std::endl;   //prints "2"
}

DEMO

The reference count after calling the setter is 2. The shared_ptr<void> acts like a normal shared-pointer in that it keeps the AA-object alive, or destroys it object properly if the pointer goes out of scope (and is itself the last one ointing to the given AA).

That works, because the deleter of the original shared-pointer has been copied which knows who to do the destruction.


EDIT2: To answer the questions in the code of the OP:

objB->setter(objA);
//status of allocated int in class AA here?

The shared-pointer inside AA is not affected at all.

//some code later
AA *objA_2 = (AA*)objB->getter();
//status of allocated int in class AA here?

Again, the shared-pointer is unaffected. This step, however, required care: if the original object is not alive anymore, you'll get a dangling pointer. Thus, better use a shared-pointer.

shared_ptr<int> p2 = objA_2->get_aptr();
//is this allowed

If the pointer is valid, of course.

One thing I didn't get is why you use smart-pointers inside the class, but raw pointers outside. Is there a reason for that?

Community
  • 1
  • 1
davidhigh
  • 14,652
  • 2
  • 44
  • 75
  • "The void * here acts an observing pointer. It does not affect the shared pointer at all, because the shared pointer doesn't know the raw pointer to its contained object even exists." Exactly, and that is my concern- we can not delete void* variable, and enclosed shared_ptr never gets out of scope. This results in huge memory leakage. Please correct if I am wrong – Apporve Jun 01 '15 at 09:29
  • @Apporve: yes, that is the bad thing with this design choice. Use a shared_ptr instead. It will correctly destroy your object. I'll make an edit to show that more clearly. – davidhigh Jun 01 '15 at 09:45
  • @ davidhigh: brilliant explanation, very helpful for understanding. But doesnt resolve my problem- I am using a 3rd party library, which forces me to use void* class variable and its getter, setter (setUserData, getUserData for Node Class, in cocos2dx). This is causing memory leaks. Can you please suggest something to avoid it without changing given conditions (only raw void* to be used, not shared_ptr). – Apporve Jun 01 '15 at 12:29
  • @ davidhigh: Thanks anyway for your explantion, I never knew that shared pointer could be used for void* too. Though not a fan of void*, will use this when forced to :) – Apporve Jun 01 '15 at 12:30
  • @Apporve: I'll try to help you when you state what you want to do. Questions: (i) the example in the original question shows no problem, i.e. there is no memory leak (--at least if you properly call `delete` on `objA` and `objB`). Can you edit it in order to clarify your problem? (ii) The shared pointer in `AA` is deleted when the destructor of `AA` is called. So your problem seems to be the lifetime of `AA`, not that of the shared pointer inside? Can you use `shared_ptr` in the `main`? (iii) deleting a `void *` is discouraged, see [here](http://stackoverflow.com/a/941959/2412846). – davidhigh Jun 01 '15 at 14:44
  • Thanks for your efforts. – Apporve Jun 02 '15 at 05:17
  • i.I cannot call delete when shared_ptr is involved. Have edited my problem, please refer. (ii) Even when object of class AA is declared as shared_ptr, it has to be cast down to simple void* to pass to setter of class BB- [ (void*)(objA.get()) ], removing its auto delete property. I am badly struck :( . – Apporve Jun 02 '15 at 05:23
  • Got it. I should have done smpl->reset(); instead of delete smpl; Thanks @davidhigh for your help. – Apporve Jun 02 '15 at 05:59