How to remove a new pointer declared by function parameters?

My class has a member function that takes a pointer of its own type as an argument.

When I do this:

Object* obj1 = new Object(); Object* obj2 = new Object(); obj1->add_child(obj2) delete obj1; delete obj2; obj1 = NULL; obj2 = NULL; 

and run valgrind , the report says:

 HEAP SUMMARY: in use at exit: 72,704 bytes in 1 blocks total heap usage: 6 allocs, 5 frees, 73,098 bytes allocated LEAK SUMMARY: definitely lost: 0 bytes in 0 blocks indirectly lost: 0 bytes in 0 blocks possibly lost: 0 bytes in 0 blocks still reachable: 72,704 bytes in 1 blocks suppressed: 0 bytes in 0 blocks 

I read the answer , says that still reachable in order, without leakage. Then when I try this:

 Object* obj = new Object(); obj1->add_child(new Object()); delete obj; obj = NULL; 

valgrind report says:

 HEAP SUMMARY: in use at exit: 72,877 bytes in 3 blocks total heap usage: 6 allocs, 3 frees, 73,098 bytes allocated LEAK SUMMARY: definitely lost: 144 bytes in 1 blocks indirectly lost: 29 bytes in 1 blocks possibly lost: 0 bytes in 0 blocks still reachable: 72,704 bytes in 1 blocks suppressed: 0 bytes in 0 blocks 

Obviously, I did not delete the new Object() pointer, which was passed as an argument. So how to remove this pointer?

DETAILED UPDATE

add_child(Object* obj) definition add_child(Object* obj) :

 void add_child(Object* obj) { container.add_child(obj); } 

container is a member of Object , which is an instance of the template class.

 Container<Object> container; 

container definition:

 template<class T> class Container { public: void add_child(const std::string& key, T* child) { childrens.insert(std::pair<std::string,T*>(key, child)); } private: std::multimap<std::string,T*> childrens; } 

Then the children are actually std::multimap .

Hope this is not too long for the question.

+1
source share
3 answers

You need to make clear and consistent choices about who owns the pointers. If you decide that add_child gets ownership, then the caller should expect that they will not need to delete the passed pointer. If you decide that add_child then the caller retains ownership and deletes the pointer.

You can force Object to take ownership, so its destructor deletes all child pointers that have been added to it. Then your first example should read

 Object* obj1 = new Object(); Object* obj2 = new Object(); obj1->add_child(obj2); delete obj1; // also deletes obj2 automatically 

and your second:

 Object* obj = new Object(); obj->add_child(new Object()); delete obj; // automatically deletes the unnamed pointer passed in on previous line 

If you do not want Object to take responsibility, you have a problem, since you have no way to remove new Object() in the context of the caller.

If you use smart pointers, managing ownership becomes a lot easier. add_child can take the argument std::unique_ptr<Object> .

 auto obj1 = std::make_unique<Object>(); auto obj2 = std::make_unique<Object>(); obj1->add_child(std::move(obj2)); // obj1 takes ownership // both pointers automatically deleted at scope exit auto obj = std::make_unique<Object>(); obj->add_child(std::make_unique<Object>()); // both pointers automatically deleted at scope exit 
+3
source

Once the function call is finished, you will no longer have the pointer created by new . If the function you are calling does not delete the pointer, then you have a memory leak.

+2
source

The valgrind message about your still available block of memory is not your fault - this is a bug in gcc 5.1 .

How I came up with this:

The block size was very large ( 72704 ) and did not match the size of the selected objects, so the next time I tried to divide 72704 into 144 and 29 to see if the array of these objects is.

But it was not like neither 72704 , nor 72704-4 , nor 72704-8 (array, array + 32-bit integer for storing the size, array + 64-bit integer for storing the size) were not divisible. So, I googled " 72,704 still reachable ", which showed the question mentioned.

Other suggestions from respondents for using smart pointers (for example, std::unique_ptr and std::shared_ptr ) sound, and I also recommend using them.

+1
source

All Articles