Lets say we have a class that holds a pointer member to another object. If I delete that pointer in the destructor I get an error (and I understand why).
My question is : is it possible to overcome that without memory leaks ?
Here is a demo of what I am doing.
class A {
public:
~A() { cout<< "~A()" <<endl; }
};
class B {
A *pA;
public:
B(A* pA) {
this->pA = pA;
}
~B() {
delete pA;
cout<<"~B()"<<endl;
}
};
int main() {
A a;
{
B b2(new A()); //deletes A, deletes B, no memory leaks
}
{
B b(&a); //deletes A, error.
}
return 0;
}
First of all that's not memory leak, but an undefined behavior, a more serious issue. An attempt is made to deallocate a memory from wrong region.
One should use delete/delete[]/free() only on corresponding new/new[]/malloc().
There is no full proof and architecture independent way, just adhere to good programming practices.
May not be perfect always, but one way is to overload new and delete and hold a std::map like data structure. Whenever new is called add the pointer to it. Upon delete you can make check if the pointer exists or not, if the allocation was of type new or new[] etc..
Definitely this will affect your performance, so you need to keep it under debug mode.
You have two objects that think they own a dynamically allocated object and try to delete it. The solution is to decide who should own the object, and to implement the correct copy/assignment behaviour with the help of the appropriate smart pointer:
Do A and B deal with dynamically allocated objects at all? There is no way of knowing this from a raw pointer, so the design has to be revised to cover one case or the other. Assuming dynamic object allocation, then
Each object owns its own copy: Implement the rule of three in A or B, and have only one of the two delete. You can use a scoped pointer to simplify memory management (boost_scoped_ptr, or std::unique_ptr).
Unique ownership: a single object owns the copy: Use std::unique_ptr. Disallow copy and assignment, allow move-copy and move-assignment
Shared ownership: Nobody/everybody owns the object. It gets deleted when nobody references it: use std::shared_ptr
You must tell B, when it owns the pointer and when it doesn't.
Add an additional flag telling when
class B {
bool owner;
A *pA;
public:
B(A* pA, bool bOwner) : owner(bOwner) {
this->pA = pA;
}
~B() {
if (owner)
delete pA;
cout<<"~B()"<<endl;
}
};
int main() {
A a;
{
B b2(new A(), true); //deletes A, destroys B, no memory leaks
}
{
B b(&a, false); //destroys B, ok.
}
return 0;
}
Related
OK..so this confuses the hell out of me. I am dealing with some legacy C++ code parts of which I have a feeling are just not safe, but I am not 100% sure. Here's a snippet, for example of the risky stuff.
struct A {
A() : a_ptr(0) {}
A(some_type *ptr) : a_ptr(ptr) {}
const some_type *a_ptr;
};
struct B {
B() : b_ptr(0) {}
B(some_type *ptr) : b_ptr(ptr) {}
const some_type *b_ptr;
};
struct Data {
Data(...) {//-Stuff that doesn't invole aptr_list or bptr_list;
}
~Data() {
for(std::vector<A*>::iterator itr = aptr_list.begin(); itr != aptr_list.end() ++itr) {
delete *itr;
}
for(std::vector<B*>::iterator itr = bptr_list.begin(); itr != bptr_list.end() ++itr) {
delete *itr;
}
}
std::vector<A*> aptr_list;
std::vector<B*> bptr_list;
private:
Data(const Data&);
Data& operator=(const Data&);
};
Then in the implementation, I find:
void some_func(...) {
//-Inside some function
Data& d = get_data(...);
...
for(...) {
some_type *sptr = dynamic_cast<some_type*>(a_source_of_some_type_pointer);
A* a = new A(sptr);
B* b = new B(sptr);
d.aptr_list.push_back(a);
d.bptr_list.push_back(b);
}
}
I am a little uneasy about the same pointer sptr being used in the implementation above; would this create problems when the destructor of Data is invoked? On the other hand, it looks like we have two new calls for A* and B* and exactly two deletes, so if the destructor in Data is not deep - and maybe that's where I need clarification, then perhaps this is safe after all and my concern is misplaced? I did notice that the structs A and B for instance don't have any destructors defined, so I hope it is not deep. But I am not sure if this means their pointer data will be freed up or not. Appreciate expert insights as always.
Thanks for your time and interest.
A and B do not have a user defined destructor, so nothing INSIDE a or b gets destroyed (other than the actual memory it holds being freed up, but since sptr is just held there, it is not being deleted). [Obviously, if A or B contains some other class, say a std::string or a std::vector, that class would be destroyed].
So, in other words, your code is just fine like it is - a and b only holds a copy of sptr, but it's never deleted [in this bit of code, if it needs deleting later, that's a different matter].
Data::~Data() will not destroy sptr pointer. It will call A::~A() and B::~B() only.
I'm not sure what you want to do, but if you want a deep destruction you need to make sure you don't free a memory address which was already freed by someone before.
It depends on implementation requirements, but ideally the user who allocated the object should free as well. So since this sptr is allocated been by someone else, if you free it you might get a dangling pointer.
sptr is not owned by either A or B, so this is correct.
If we shall be really finical then the code can leak.
If d.aptr_list.push_back() needs and fails to reserve more capacity, then the memory pointed to by a and b will leak.
for(...) {
some_type *sptr = dynamic_cast<some_type*>(a_source_of_some_type_pointer);
A* a = new A(sptr); // Allocate memory
B* b = new B(sptr) // Allocate memory (and missing semicolon!!)
d.aptr_list.push_back(a); // If this fails,
d.bptr_list.push_back(b); // or this,
} // then exception is thrown and memory is lost
// (unless you catch the exception and
// perform a delete).
You should use a smart pointer like std::unique_ptr to wrap around the pointers for safety.
Your lists should be of type std::vector<std::unique_ptr<A>> and std::vector<std::unique_ptr<B>>.
In some_func the code could read something like this:
some_type *sptr = dynamic_cast<some_type*>(a_source_of_some_type_pointer);
d.aptr_list.push_back(std::unique_ptr<A>(new A(sptr)));
d.bptr_list.push_back(std::unique_ptr<B>(new B(sptr)));
This is a simplified version of some code that I have. Since pointerB in class A is set to pointer, beta, in the client code which points to allocated memory, would i have to free the memory pointed by pointerB in the destructor of class A once it is deleted as well?
class A{
public:
A(B* beta){
pointerB = beta;
}
~A(){
/*
would deleting pointerB be necessary
*/
}
B* pointerB;
};
class B{
public:
B();
};
//client code
B* beta = new B();
A* alpha = new A(beta);
//do stuff
delete beta;
delete alpha;
beta = NULL;
alpha = NULL;
For every new there has to be one and only one delete during the execution of your application.
So it doesn't matter whether delete pointerB is called in the destructor or delete beta is called outside as you did. Because it is the same memory that is freed here! The question is if A "owns" an instance of B (and thus is responsible for freeing the memory it uses) or if A only has a reference to an instance of B (and is for example deleted when beta is still used).
BUT (as Roger already pointed out) I suggest reading the documentation to std::shared_ptr and std::unique_ptr. Here for example: http://en.cppreference.com/w/cpp/memory In most cases you can make good use of these and then you don't have to care for memory management.
It looks like objects of type A retain a pointer to a B object but don't own a B. This is fine and A's destructor shouldn't attempt to delete the B object.
Given this model, the client should ensure that the B object passed by pointer to A's constructor remains in existence throughout the lifetime of the A object. Your client code fails to do this but if you completely avoid dynamically allocating objects, achieving this is simple and natural and removes any possibility of leaking objects.
E.g.
void client()
{
B b;
A a(&b);
// do stuff
// Because we constructed `a` after we constructed `b` in this scope
// we are guarateed that `a` will be destroyed before `b` (reverse order)
// and the pointer that `a` is holding will never point to a destroyed
// object.
}
The assignment in the constructor of A: pointerB = beta; does not allocate new memory. Therefore, you do not need to de-allocate it when calling the destructor of A.
However, this behavior is risky:
B* beta = new B(); // memory for B is allocated
A alpha( B ); // local instance. A.pointerB points to beta
delete beta; // memory de-allocated
// risky part: alpha.pointerB still points to where beta was allocated
// BUT THIS MEMORY IS ALREADY FREED!
You need to carefully think about this.
Your example can be simplified to this:
struct A{};
int main()
{
A* wtf= new A;
A* omg= wtf;
delete wtf;
}
Is correct and so is this:
struct A{};
int main()
{
A* wtf= new A;
A* omg= wtf;
delete omg;
}
Deleting both is a double delete error, don't do this:
delete omg;
delete wtf;
You would be trying to deallocate the same memory both pointers are pointing at, twice!
When you allocate memory dynamically you have to release it.
When you do new B() You allocate memory for the object dynamically and then assign the address to beta which is of type B*. This is a pointer to that memory. When you do delete beta, you delete the memory that was allocated. This memory can be pointed by many pointers (like the one in your constructor )BUT you need to delete only once. But if you make attempts to use the other pointers (dereferencing etc.) you can blow your code.
Only when you do new you allocate memory. [Your code must contain equal and corresponding number of delete] which has to be released
Consider this way, you have a place for storing data and several labels pointing to the location of that place. Now if using one label you destroy the place, the other labels will still be having the location. But now its useless since the place is inexistent now.
The whole idea is, if you allocate something from heap, you should deallocate it and it should be done only once, and, you shouldn't access the memory after it is deallocated.
In order to achieve this, we usually make allocation and deallocation to be done by same component. For example, if you allocate a piece of memory in class Foo, do the deallocation there too. However, it is only a convention to make things less error-prone. As long as you are sure that the deallocation is going to happen, and happen only once, everything is fine.
Using shared_ptr or similar facilities is also a way to ensure this behavior.
Going back to your specific example, we cannot say whether you should do the deallocation in A. What I can say is, as you have delete beta done in your main() already, if you do the deallocation both in A and main() then it is a problem.
Whether you should deallocate in A or leave it to the caller depends on your design.
You have to delete it in destructor of A. There is a sample program you can test both conditions by
1. Run the program still value of b exists means you have to delete it in destructor of A.
2. Uncomment delete b line in the code and you will see b is free.
class B;
class A
{
B * b;
public:
A(B * obj)
{
b = obj;
}
~A()
{
//delete b;
}
};
class B
{
int value;
public:
B()
{
value = 10;
}
~B()
{
}
int getValue(){return value;}
};
void main()
{
B *b = new B;
A * a = new A(b);
delete a;
cout<<"B exists: "<<b->getValue();
}
Here's my structure A
struct A {
int a1;
int a2;
~A() { }
};
B is another structure that contains a pointer to A
struct B {
B(int b, A* a)
: b1(b), ptr2A(a)
{}
int b1;
A* ptr2A;
~B() {
delete b1;
// traverse each element pointed to by A, delete them <----
}
};
Later on I use below code
int bb1;
vector <A*> aa1;
// do some stuff
B *ptrB = new B(bb1, aa1);
I need to delete/free all the memory pointed to by ptrB. Hence I need to write correct destructor inside struct B. How do I traverse each element pointed to by A and delete them?
If you're using a C++11 compiler, just use std::shared_ptr and you don't have to worry about deletes. This is because the shared_ptr is a "smart" pointer that will automatically delete what its pointing to.
#include <memory>
struct B
{
int b1;
std::shared_ptr<A> ptr2A;
B(int b, std::shared_ptr<A> a):b1(b),ptr2A(a)({}
~B(){} //look ma! no deletes!
};
Use a shared pointer whenever you allocate something:
#include<memory>
...
{
....
std::shared_ptr<B> ptrB( new B(bb1, aa1) );
//Here is another, more readable way of doing the same thing:
//auto ptrB = std::make_shared<B>(bb1,aa1);
...
}
//no memory leaks here, because B is automatically destroyed
Here's more info on the subject of smart pointers.
I should also mention that if you don't have a C++11 compiler, you can get shared pointers from the BOOST library.
You need only to delete objects allocated by new. In this case there's no need to delete b1 as it has not been dynamically-allocated. Moreover, if you did not initialize ptr2a with dynamic memory, deleting it is undefined behavior.
So there's no need to worry about deleting As data as it will be destructed from memory along wih the instance of the class.
You've only got one pointer to A. So you only need to delete that:
~B() {
delete ptr2A;
}
Note that you can't delete b1, since it's a plain int! (The memory taken up by the variables of the structure, such as b1 and the pointer ptr2A itself (not what it points to) are destroyed automatically along with any instances of that structure.)
I am beginning to teach myself C++ and how to handle objects without a garbage collector is causing me some confusion. Here is a simple case of what I am trying to do:
A* a;
B b = new B(a); // Note that B is a derived class of A
a = &b;
while (a != NULL)
{
(*a).run();
}
This all works as I expect it to. Where I am having the issue, is that inside the run() method of B, I want to do something like:
C c = new C(a); // a is the same pointer as above, that has been stored
// and C another derived class from A
a = &c;
and then let run() exit. The while loop in the first block would then call would call run() on the new object. My question is, how do I make sure that the memory from the original b is correctly de-allocated?
You could use std::shared_ptr in this case. If two classes have members which need to point to the same object, then you can make both of them shared_ptr. And you do this usually, however if while doing so, if you about to create cyclic-dependency, then to break that cyclic-dependency, you need std::weak_ptr.
Here is example of std::shared_ptr and std::weak_ptr.
WRONG CODE (cyclic-dependency):
struct B;
struct A
{
std::shared_ptr<B> bp;
}
struct B
{
std::shared_ptr<A> ba; //this creates a cyclic dependency.
}
CORRECT CODE (non-cyclic):
struct B;
struct A
{
std::shared_ptr<B> bp;
}
struct B
{
std::weak_ptr<A> ba; //break cyclic dependency with std::weak_ptr
}
Whenever you're faced with dynamic memory allocation and nontrivial ownership semantics, smart pointers are often a good way to ensure correctness.
See, for example, std::shared_ptr.
Suppose I create a form using a pointer and that form contains sub item as another pointer, when I delete the form, I perform a delete operation on the main pointer, do I need to perform a delete operation on the sub pointer also or the compiler does that on its own?
If you're the one allocating memory for the pointer, yes, you need to explicitly release all memory you're allocating.
struct A
{
};
struct B
{
A* a;
B() { a = new A; }
~B();
};
B* b = new B;
delete b;
//you will have a memory leak here, since the memory pointed to by b.a
//is not released
The proper way is freeing the memory in the destructor:
struct B
{
A* a;
B() { a = new A; }
~B() { delete a; }
};
You should read up on smart pointers, they might suit your case better.
Yes, you'll normally need to delete that explicitly to avoid a memory leak. Simple rule: if you used new to allocate it, you'll need a matching delete to free it.
That said, you usually want to use something like a smart pointer that handles all this automatically.
This question hinges on the way the destructor for the form is written. For example, the form may try to call the destructor for the sub-form. If it performs this kind of cleanup then you do not need to further release the sub-form. It would be informative to know what form management system you are talking about (for example MFC).