1

I am having a situation where I have to call a function in loop with pointer (to a class object) as a parameter. Issue is, I cannot modify the signature of that function and that with every iteration of loop, I have to initialize the pointer. This will lead to memory leak as I cannot delete the pointer (after passing it to the function) inside the loop. Is there any way I can prevent memory leak in such a case?

I would like to explain with a simple example:

class testDelete
{
    public:
        void setValue(int* val) {vec.push_back(val);};
        void getValue();
    private:
        vector <int*> vec;
};
void testDelete::getValue()
{
    for (int i=0;i<vec.size();i++)
    {
        cout << "vec[" << i << "] = " << *vec[i]<<"\n";
    }
}

int main()
{
    testDelete tD;
    int* value = NULL;
    for (int i=0;i<10;i++)
    {
        value=new int(i+1);
/*I am not allowed to change this function's signature, and hence I am forced to pass pointer to it*/
        tD.setValue(value); 
/*I cannot do delete here otherwise the getValue function will show garbage value*/ 
        //delete value;
    }

    tD.getValue();
    return 0;
}
Ashish
  • 83
  • 1
  • 7
  • 1
    related/dupe: https://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one – NathanOliver Apr 04 '19 at 17:51
  • Doesn't matter what vec holds, the issue is that setValue function expects a pointer and I cannot update it's signature, so I am having to initialize pointer in a loop and pass it to the function. Again, it is just an example to show the scenario. – Ashish Apr 04 '19 at 17:51
  • 1
    Nothing here prevents you from deleting that value later, when it is not needed anymore or using `unique_ptr` – user7860670 Apr 04 '19 at 17:52
  • 1
    @user463035818 Populating vector with dangling pointers or pointers to the same value does not seem like a good suggestion. – user7860670 Apr 04 '19 at 17:53
  • @VTT, where can I delete it as the value is later used in another function and if I do the delete (which I have commented), getValue will show garbage values instead of the actual ones. – Ashish Apr 04 '19 at 17:58
  • delete them just prior to `return 0`; – user7860670 Apr 04 '19 at 17:59
  • You can delete the pointers in the destructor of the class. But you also need to investigate the **rule of three** for when your class objects get copied. – Galik Apr 04 '19 at 18:06
  • @VTT, yes I can delete them after the getValue function is done calling, however, it is not the case I can implement in the actual code, as there, the invocations are happening from other classes and function to which pointers are passed belong to another class. Your suggestion is correct with regards to the example I have shared though. :) – Ashish Apr 04 '19 at 18:24

2 Answers2

2

If deleteTest wants to use pointers of maybe gone objects it should hold std::weak_ptrs. Holding on to a raw pointer and dereferencing it later is dangerous (unless you can make sure the object is still alive, a.k.a don't use raw but smart pointers).

[...] I cannot modify the signature of that function and that with every iteration of loop, I have to initialize the pointer. Is there any way I can prevent memory leak in such a case?

If you need dynamically allocated objects, use smart pointers (eg std::smart_ptr for shared ownership). If you do not need to dynamically allocate them then don't.

For the sake of the example lets assume you cannot modify deleteTest, then for integers there is no reason to dynamically allocate anything

int main()
{
    std::array<int,10> x;
    testDelete tD;        
    for (int i=0;i<10;i++)
    {
        x[i] = i+1;
        tD.setValue(&x[i]); 
    }    
    tD.getValue();
    return 0;
}

Take this code with a grain of salt, it is actually deleteTest that needs to be fixed to avoid creating trouble.

TL;DR

In your example you have actually two problems. deleteTest may try to access already gone objects and memory leaks in main. Using smart pointers solves both.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Preferably declare the array before `tD` so that it won't get destroyed during the lifetime of `td`. The destructor doesn't touch the integers, so this is technically not a problem, but it doesn't hurt to be safe. – eerorika Apr 04 '19 at 18:01
  • _"Now it seems like, testNonOwning doesnt really want to participate in ownership, but rather expects a raw pointer."_ Well, wasn't using a `std::weak_ptr` the right idiom to solve that? – πάντα ῥεῖ Apr 04 '19 at 18:11
2

Store the integers in a container:

int main()
{
    std::vector<int> values(10);

    testDelete tD;
    for (int i=0;i<10;i++)
    {
        values[i] = i + 1;
        tD.setValue(&values[i]);
    }

    tD.getValue();
    return 0;
}
eerorika
  • 232,697
  • 12
  • 197
  • 326