I've been trying to figure this out but can't quite get my head round it.
Say I declare an object in a header file such as:
#ifndef SOMECLASS_H
#define SOMECLASS_H
#include "otherclass.h"
class SomeClass
{
public:
SomeClass();
OtherClass *obj;
};
#endif // SOMECLASS_H
Can I do the following in my code?
obj = new OtherClass();
//Do something
delete obj;
obj = new OtherClass();
//Do something else
delete obj;
Or would I have to create a new obj?
I can't really think of a reason why I might need to do this but I'd like to know if it would work and also whether or not it would be a good idea (I know it's best to create objects on the stack generally but for the sake of argument let's say in this case it isn't an option).
I think you need to adjust your mental model of what's happening. Let's look at a simpler case where we don't have the SomeClass class:
int main() {
OtherClass *obj = new OtherClass();
delete obj;
obj = new OtherClass();
delete obj;
}
The first line is this function is a declaration. This declaration introduces an object called obj whose type is OtherClass*. The important thing here is that obj is just a pointer. It's not an OtherClass object. It just holds the address of one. So when you talk about the object obj, you are talking about the pointer.
This declaration has an initialiser which is = new OtherClass(). The expression new OtherClass() also introduces an object, but this time it is not named. This object has type OtherClass. The expression returns a pointer to that OtherClass object which you are using to initialise obj. So now the obj pointer object is pointing at the OtherClass object.
The memory model for this looks something like this:
obj
+-------------+ +------------+
| OtherClass* |----->| OtherClass |
+-------------+ +------------+
Now, you can use an object during its lifetime. The lifetime of obj is the scope of the function we declared it in. At the end of the function, obj goes out of scope and is destroyed. That is, the pointer is destroyed. The lifetime of the OtherClass object lasts up until we use delete on a pointer to it. The delete only destroys the OtherClass object and not the pointer. So after the first delete, we have this:
obj
+-------------+
| OtherClass* |----->
+-------------+
The pointer still exists. It's still pointing to the same place even, but the object that was there is now gone.
At this point, we can't attempt to use the OtherClass object, since it doesn't exist any more. However, we can certainly reuse the pointer object obj. When we do obj = new OtherClass() (which is an expression, not a declaration), we create a new OtherClass object and set obj to point at it. We're back to this situation:
obj
+-------------+ +------------+
| OtherClass* |----->| OtherClass |
+-------------+ +------------+
And then we delete it again.
The only difference between this example and your example is that obj is a member of SomeClass. Each object of type SomeClass will contain within it an OtherClass* pointer called obj. The lifetime of obj now is whatever the lifetime of the SomeClass object is. As long as that object is still alive, you can use obj in whatever way you like. Of course, if you delete the object it is pointing at, you cannot use that object.
Your code is ok.
If you want you can reuse your pointer any time you want.
obj = new OtherClass();
delete obj;
obj = new OtherClass();
remeber that when you call delete you call OtherClass destructor.
it is good practice, but not required, put pointer to zero after delete.
obj = 0;
This because, if after delete pointer you want to test, for instance
if(!obj) {
...
}
it is said that !obj == true.
Your code is fine, but in C++11 consider using unique_ptr to avoid having to call "delete" manually. Eg:
std::unique_ptr<OtherClass> obj(new OtherClass());
//Do something
obj.reset(new OtherClass()); //this deletes the previous object
//Do something else. The object will be deleted when obj goes out of scope.
Also you might want to consider changing your title to something like, "Can I reassign a pointer after deleting the object it points to?"
Yes it would work. When you do the second
obj = new OtherClass();
the obj points to deleted memory, but you set it to new value. There is nothing wrong with it.
Your code is fine.
Depending on how OtherClass works, you may consider doing:
obj = new OtherClass();
//Do something
// then do something else
delete obj;
But this is not always feasible. Should this not be applicable in your case, what you are currently doing is OK.
I'd just do obj = NULL; after the second delete. Just in case I need to test this pointer's value somewhere else, to determine whether it is in use or not.
To sum up : you can't use an instance of a class that has been deleted, but you can reuse the variable pointer which was used to store the address of the instance.
That is to say, you CANNOT do the following (from your code sample) :
obj = new OtherClass();
delete obj;
obj->objMethod(); // dereferencing a now invalid pointer => dangerous.
But you can do what you wrote in your question :
obj = new OtherClass();
//Do something
delete obj;
obj = new OtherClass();
//Do something else
delete obj;
Actually, the last sample of code is as valid as the following (with a simple int) :
int i = 42;
// Do something
i = 15;
// Do something
Related
I learned C# first, and now I'm starting with C++. As I understand, operator new in C++ is not similar to the one in C#.
Can you explain the reason of the memory leak in this sample code?
class A { ... };
struct B { ... };
A *object1 = new A();
B object2 = *(new B());
What is happening
When you write T t; you're creating an object of type T with automatic storage duration. It will get cleaned up automatically when it goes out of scope.
When you write new T() you're creating an object of type T with dynamic storage duration. It won't get cleaned up automatically.
You need to pass a pointer to it to delete in order to clean it up:
However, your second example is worse: you're dereferencing the pointer, and making a copy of the object. This way you lose the pointer to the object created with new, so you can never delete it even if you wanted!
What you should do
You should prefer automatic storage duration. Need a new object, just write:
A a; // a new object of type A
B b; // a new object of type B
If you do need dynamic storage duration, store the pointer to the allocated object in an automatic storage duration object that deletes it automatically.
template <typename T>
class automatic_pointer {
public:
automatic_pointer(T* pointer) : pointer(pointer) {}
// destructor: gets called upon cleanup
// in this case, we want to use delete
~automatic_pointer() { delete pointer; }
// emulate pointers!
// with this we can write *p
T& operator*() const { return *pointer; }
// and with this we can write p->f()
T* operator->() const { return pointer; }
private:
T* pointer;
// for this example, I'll just forbid copies
// a smarter class could deal with this some other way
automatic_pointer(automatic_pointer const&);
automatic_pointer& operator=(automatic_pointer const&);
};
automatic_pointer<A> a(new A()); // acts like a pointer, but deletes automatically
automatic_pointer<B> b(new B()); // acts like a pointer, but deletes automatically
This is a common idiom that goes by the not-very-descriptive name RAII (Resource Acquisition Is Initialization). When you acquire a resource that needs cleanup, you stick it in an object of automatic storage duration so you don't need to worry about cleaning it up. This applies to any resource, be it memory, open files, network connections, or whatever you fancy.
This automatic_pointer thing already exists in various forms, I've just provided it to give an example. A very similar class exists in the standard library called std::unique_ptr.
There's also an old one (pre-C++11) named auto_ptr but it's now deprecated because it has a strange copying behaviour.
And then there are some even smarter examples, like std::shared_ptr, that allows multiple pointers to the same object and only cleans it up when the last pointer is destroyed.
A step by step explanation:
// creates a new object on the heap:
new B()
// dereferences the object
*(new B())
// calls the copy constructor of B on the object
B object2 = *(new B());
So by the end of this, you have an object on the heap with no pointer to it, so it's impossible to delete.
The other sample:
A *object1 = new A();
is a memory leak only if you forget to delete the allocated memory:
delete object1;
In C++ there are objects with automatic storage, those created on the stack, which are automatically disposed of, and objects with dynamic storage, on the heap, which you allocate with new and are required to free yourself with delete. (this is all roughly put)
Think that you should have a delete for every object allocated with new.
EDIT
Come to think of it, object2 doesn't have to be a memory leak.
The following code is just to make a point, it's a bad idea, don't ever like code like this:
class B
{
public:
B() {}; //default constructor
B(const B& other) //copy constructor, this will be called
//on the line B object2 = *(new B())
{
delete &other;
}
}
In this case, since other is passed by reference, it will be the exact object pointed to by new B(). Therefore, getting its address by &other and deleting the pointer would free the memory.
But I can't stress this enough, don't do this. It's just here to make a point.
Given two "objects":
obj a;
obj b;
They won't occupy the same location in memory. In other words, &a != &b
Assigning the value of one to the other won't change their location, but it will change their contents:
obj a;
obj b = a;
//a == b, but &a != &b
Intuitively, pointer "objects" work the same way:
obj *a;
obj *b = a;
//a == b, but &a != &b
Now, let's look at your example:
A *object1 = new A();
This is assigning the value of new A() to object1. The value is a pointer, meaning object1 == new A(), but &object1 != &(new A()). (Note that this example is not valid code, it is only for explanation)
Because the value of the pointer is preserved, we can free the memory it points to: delete object1; Due to our rule, this behaves the same as delete (new A()); which has no leak.
For you second example, you are copying the pointed-to object. The value is the contents of that object, not the actual pointer. As in every other case, &object2 != &*(new A()).
B object2 = *(new B());
We have lost the pointer to the allocated memory, and thus we cannot free it. delete &object2; may seem like it would work, but because &object2 != &*(new A()), it is not equivalent to delete (new A()) and so invalid.
In C# and Java, you use new to create an instance of any class and then you do not need to worry about destroying it later.
C++ also has a keyword "new" which creates an object but unlike in Java or C#, it is not the only way to create an object.
C++ has two mechanisms to create an object:
automatic
dynamic
With automatic creation you create the object in a scoped environment:
- in a function or
- as a member of a class (or struct).
In a function you would create it this way:
int func()
{
A a;
B b( 1, 2 );
}
Within a class you would normally create it this way:
class A
{
B b;
public:
A();
};
A::A() :
b( 1, 2 )
{
}
In the first case, the objects are destroyed automatically when the scope block is exited. This could be a function or a scope-block within a function.
In the latter case the object b is destroyed together with the instance of A in which it is a member.
Objects are allocated with new when you need to control the lifetime of the object and then it requires delete to destroy it. With the technique known as RAII, you take care of the deletion of the object at the point you create it by putting it within an automatic object, and wait for that automatic object's destructor to take effect.
One such object is a shared_ptr which will invoke a "deleter" logic but only when all the instances of the shared_ptr that are sharing the object are destroyed.
In general, whilst your code may have many calls to new, you should have limited calls to delete and should always make sure these are called from destructors or "deleter" objects that are put into smart-pointers.
Your destructors should also never throw exceptions.
If you do this, you will have few memory leaks.
B object2 = *(new B());
This line is the cause of the leak. Let's pick this apart a bit..
object2 is a variable of type B, stored at say address 1 (Yes, I'm picking arbitrary numbers here). On the right side, you've asked for a new B, or a pointer to an object of type B. The program gladly gives this to you and assigns your new B to address 2 and also creates a pointer in address 3. Now, the only way to access the data in address 2 is via the pointer in address 3. Next, you dereferenced the pointer using * to get the data that the pointer is pointing to (the data in address 2). This effectively creates a copy of that data and assigns it to object2, assigned in address 1. Remember, it's a COPY, not the original.
Now, here's the problem:
You never actually stored that pointer anywhere you can use it! Once this assignment is finished, the pointer (memory in address3, which you used to access address2) is out of scope and beyond your reach! You can no longer call delete on it and therefore cannot clean up the memory in address2. What you are left with is a copy of the data from address2 in address1. Two of the same things sitting in memory. One you can access, the other you can't (because you lost the path to it). That's why this is a memory leak.
I would suggest coming from your C# background that you read up a lot on how pointers in C++ work. They are an advanced topic and can take some time to grasp, but their use will be invaluable to you.
Well, you create a memory leak if you don't at some point free the memory you've allocated using the new operator by passing a pointer to that memory to the delete operator.
In your two cases above:
A *object1 = new A();
Here you aren't using delete to free the memory, so if and when your object1 pointer goes out of scope, you'll have a memory leak, because you'll have lost the pointer and so can't use the delete operator on it.
And here
B object2 = *(new B());
you are discarding the pointer returned by new B(), and so can never pass that pointer to delete for the memory to be freed. Hence another memory leak.
If it makes it easier, think of computer memory as being like a hotel and programs are customers who hire rooms when they need them.
The way this hotel works is that you book a room and tell the porter when you are leaving.
If you program books a room and leaves without telling the porter the porter will think that the room is still is use and will not let anyone else use it. In this case there is a room leak.
If your program allocates memory and does not delete it (it merely stops using it) then the computer thinks that the memory is still in use and will not allow anyone else to use it. This is a memory leak.
This is not an exact analogy but it might help.
When creating object2 you're creating a copy of the object you created with new, but you're also losing the (never assigned) pointer (so there's no way to delete it later on). To avoid this, you'd have to make object2 a reference.
It's this line that is immediately leaking:
B object2 = *(new B());
Here you are creating a new B object on the heap, then creating a copy on the stack. The one that has been allocated on the heap can no longer be accessed and hence the leak.
This line is not immediately leaky:
A *object1 = new A();
There would be a leak if you never deleted object1 though.
I have the following code:
vector<SomeClass> objs;
SomeClass obj; // create a new obj with a new name
objs.push_back(obj);
while (someConditionIsTrue()){
use(&obj);
obj = new SomeClass(); // create a new obj with an existing name
objs.pushback(obj)
}
in this code new SomeClass(); is in java OOP form - and is not a c++ code. what code should be used instead of obj = new SomeClass();?
The answer is:
obj = SomeClass();
new SomeClass() will return pointer to SomeClass object. You cannot assign it to varible obj, which type is SomeClass, not SomeClass*.
EDIT: If I remember well, SomeClass obj(); should also work.
I think what you wanted is something like that:
vector<SomeClass *> objs;
SomeClass* obj = new SomeClass; // create a new obj with a new name
objs.push_back(obj);
while (someConditionIsTrue())
{
use(&obj);
obj = new SomeClass; // create a new obj with an existing name
objs.push_back(obj)
}
Your understanding of the language is somewhat off. Here is your code as annotated:
vector<SomeClass> objs;
SomeClass obj; // create a new obj with a new name
objs.push_back(obj);
while (someConditionIsTrue()){
use(&obj);
obj = new SomeClass(); // create a new obj with an existing name
objs.pushback(obj)
}
Here is what ACTUALLY happens
// create an object called "objs" which is a std::vector header, on the stack.
vector<SomeClass> objs;
// create an instace of "SomeClass" on the stack, call it obj.
SomeClass obj;
// allocate storage in the heap for some number of SomeClass instances to
// act as the storage for "objs", and assign them to it's "m_data" member.
// default construct the first one,
// then call it's copy constructor with the stack instance of "Obj" to
// copy the values/data into the first entry of the heap allocation of objs.
objs.push_back(obj);
while (someConditionIsTrue()){
// pass a pointer to the stack-allocated instance of obj.
use(&obj);
// create a new instance of "SomeClass" on the heap,
// default/zero construct it,
// return the pointer to this heap allocation and pass it
// to obj.operator=(const SomeClass*) to copy the data into
// the stack space allocated for "obj".
obj = new SomeClass(); // create a new obj with an existing name
// leak the pointer to the previous heap allocation by not storing it.
// increase the size of the heap allocation backing objs and then
// default construct the first SomeClass instance in the new space,
// then copy our freshly copy-initialized stack instance back into it.
objs.pushback(obj)
}
You could write this code numerous other ways, but it seems like the most sensible would be.
std::vector<SomeClass> objs;
while (someConditionIsTrue()) {
objs.resize(objs.size() + 1); // grow me a new element.
use(&objs.back());
}
Or make "use" take a reference.
void use(SomeClass& obj);
//...
use(objs.back());
If you really want a local object to try the entry.
while (someConditionIsTrue()) {
objs.resize(objs.size() + 1);
// the compiler will either optimize this out entirely,
// or use a pointer under the hood.
SomeClass& obj = objs.back();
use(&obj); // take the address of the object obj references.
}
Also, be aware that "resize()" can get expensive. You might want to do this upfront:
objs.reserve(1024); // or something you know is likely to cover most use cases.
If you really, really have to use a pointer.
SomeClass* obj = nullptr;
while (someConditionIsTrue()) {
objs.resize(objs.size() + 1);
obj = &objs.back();
use(obj);
}
Instead of "objs.resize()" you may be able to use placement-new with a ctor:
objs.emplace_back(SomeClass());
Others have suggested that you use
obj = Someclass();
But note that this is copying a default-constructed stack copy of the object.
{
SomeClass tempObj;
obj.operator=(std::move(tempObj));
}
I don't think that's what you actually want to do. It's more expensive than just having a stack-local copy like this:
while (someCondition()) {
SomeClass stackCopy;
...
}
the compiler is smart enough not to give up the stack space each loop. What it will do is a thing called "Placement new" to re-invoke the constructor on the same object:
SomeClass obj;
while (someCondition()) {
new (&obj) SomeClass(); // Call SomeClass() ctor on the memory at &obj
...
}
But - this is basically how the compiler achieved my previous code sample.
I have the following code:
void someFunction() {
.......
myClass obj= *(new myClass());
........
delete &obj;
}
I get a runtime error saying invalid pointer.
The code runs fine without the "delete" line.
I know that I need to re-claim memory allocated dynamically by new operator. But I don't know what is going on in this case and how or even do I need to free the memory?
Thanks
If your intent is for the instance to only exist within the scope of this function, then you don't need to use dynamic allocation...
void someFunction() {
.......
myClass obj;
........
}
... in which case the obj constructor is called when it is declared at myClass obj and the destructor is called when the function returns. Otherwise, if it must be dynamic, then this...
void someFunction() {
.......
myClass* obj = new myClass();
........
delete obj;
}
... in which case the constructor is called when you call new myClass() and the destructor is called when you call delete obj -- but, in this case, you need to declare obj to be a pointer to a myClass object so that there's a place to store the return value from the new.
In your example I don't think you can re-claim the memory.
obj is a copy of the anonymous class you create with *(new myClass()). "obj" is allocated on the stack... it is not allocated on the heap (which is where new allocates from).
When you try to delete &obj you are trying to delete the stack memory for the copy that you created.
Try something like
myClass *obj = new myClass(); // memory is allocated from the heap and a pointer returned
myClass copyOfObj = *obj; // memory is allocated on the stack. a *shallow* copy of obj is made
delete obj.
myClass obj= *(new myClass());
That line:
Creates an instance of myClass with automatic storage duration.
Dynamically allocates an instance of myClass.
Dereferences the returned pointer and copies the object to obj. The pointer to the dynamically allocated object is discarded, resulting in a memory leak.
Call delete on a pointer to a local variable with automatic storage duration, which results in undefined behavior. This object was not allocated with new or any variant of new.
Your code should be:
myClass *p = new myClass();
// use p
delete p;
You probably don't need dynamic memory allocation at all, so...
myClass obj; // that's it!
Next, read up on smart pointers.
std::unique_ptr<myClass> p(new myClass());
// no delete! unique_ptr handles it for you when it goes
// out of scope and has the benefit of being exception safe.
Your obj variable has to hold a reference to the dereferenced pointer, so that it later can (rather oddly) delete it:
myClass& obj;
// ^
But you need not define it this way, you can define a pointer to the memory instead:
myClass* obj = new myClass();
and delete it this way:
delete obj;
Or, better yet, you can use memory management tools like std::unique_ptr:
std::unique_ptr<myClass> obj(new myClass);
But there really is no use here for dynamic memory as far as I can see, just intantiate it as a normal variable:
myClass obj;
myClass obj= *(new myClass());
This first creates a myClass object with automatic storage duration named obj. This object is initialised by the expression *(new myClass()). This expression dynamically allocates a myClass object and then dereferences the pointer to that object. So what you end up doing here, is dynamically allocating an object and then copying that into obj.
You've now lost track of the dynamically allocated object. That's not good. Doing delete &obj; will only take the address of the automatic object and attempt to destroy that, but you must only use delete with dynamically allocated objects.
You could change obj to be a reference and it would work:
myClass& obj = *(new myClass());
This makes sure the dynamically allocated object isn't copied. However, this isn't a good idea. It masks the fact that obj refers to an object that must be deleted. Instead, you're better off storing the pointer itself:
myClass* obj = new myClass();
// ...
delete obj;
Or even better, use a smart pointer like std::unique_ptr<myClass>.
Or even betterer, don't even both dynamically allocating it. Just use an automatic object:
myClass obj;
// No need to allocate or delete anything
I learned C# first, and now I'm starting with C++. As I understand, operator new in C++ is not similar to the one in C#.
Can you explain the reason of the memory leak in this sample code?
class A { ... };
struct B { ... };
A *object1 = new A();
B object2 = *(new B());
What is happening
When you write T t; you're creating an object of type T with automatic storage duration. It will get cleaned up automatically when it goes out of scope.
When you write new T() you're creating an object of type T with dynamic storage duration. It won't get cleaned up automatically.
You need to pass a pointer to it to delete in order to clean it up:
However, your second example is worse: you're dereferencing the pointer, and making a copy of the object. This way you lose the pointer to the object created with new, so you can never delete it even if you wanted!
What you should do
You should prefer automatic storage duration. Need a new object, just write:
A a; // a new object of type A
B b; // a new object of type B
If you do need dynamic storage duration, store the pointer to the allocated object in an automatic storage duration object that deletes it automatically.
template <typename T>
class automatic_pointer {
public:
automatic_pointer(T* pointer) : pointer(pointer) {}
// destructor: gets called upon cleanup
// in this case, we want to use delete
~automatic_pointer() { delete pointer; }
// emulate pointers!
// with this we can write *p
T& operator*() const { return *pointer; }
// and with this we can write p->f()
T* operator->() const { return pointer; }
private:
T* pointer;
// for this example, I'll just forbid copies
// a smarter class could deal with this some other way
automatic_pointer(automatic_pointer const&);
automatic_pointer& operator=(automatic_pointer const&);
};
automatic_pointer<A> a(new A()); // acts like a pointer, but deletes automatically
automatic_pointer<B> b(new B()); // acts like a pointer, but deletes automatically
This is a common idiom that goes by the not-very-descriptive name RAII (Resource Acquisition Is Initialization). When you acquire a resource that needs cleanup, you stick it in an object of automatic storage duration so you don't need to worry about cleaning it up. This applies to any resource, be it memory, open files, network connections, or whatever you fancy.
This automatic_pointer thing already exists in various forms, I've just provided it to give an example. A very similar class exists in the standard library called std::unique_ptr.
There's also an old one (pre-C++11) named auto_ptr but it's now deprecated because it has a strange copying behaviour.
And then there are some even smarter examples, like std::shared_ptr, that allows multiple pointers to the same object and only cleans it up when the last pointer is destroyed.
A step by step explanation:
// creates a new object on the heap:
new B()
// dereferences the object
*(new B())
// calls the copy constructor of B on the object
B object2 = *(new B());
So by the end of this, you have an object on the heap with no pointer to it, so it's impossible to delete.
The other sample:
A *object1 = new A();
is a memory leak only if you forget to delete the allocated memory:
delete object1;
In C++ there are objects with automatic storage, those created on the stack, which are automatically disposed of, and objects with dynamic storage, on the heap, which you allocate with new and are required to free yourself with delete. (this is all roughly put)
Think that you should have a delete for every object allocated with new.
EDIT
Come to think of it, object2 doesn't have to be a memory leak.
The following code is just to make a point, it's a bad idea, don't ever like code like this:
class B
{
public:
B() {}; //default constructor
B(const B& other) //copy constructor, this will be called
//on the line B object2 = *(new B())
{
delete &other;
}
}
In this case, since other is passed by reference, it will be the exact object pointed to by new B(). Therefore, getting its address by &other and deleting the pointer would free the memory.
But I can't stress this enough, don't do this. It's just here to make a point.
Given two "objects":
obj a;
obj b;
They won't occupy the same location in memory. In other words, &a != &b
Assigning the value of one to the other won't change their location, but it will change their contents:
obj a;
obj b = a;
//a == b, but &a != &b
Intuitively, pointer "objects" work the same way:
obj *a;
obj *b = a;
//a == b, but &a != &b
Now, let's look at your example:
A *object1 = new A();
This is assigning the value of new A() to object1. The value is a pointer, meaning object1 == new A(), but &object1 != &(new A()). (Note that this example is not valid code, it is only for explanation)
Because the value of the pointer is preserved, we can free the memory it points to: delete object1; Due to our rule, this behaves the same as delete (new A()); which has no leak.
For you second example, you are copying the pointed-to object. The value is the contents of that object, not the actual pointer. As in every other case, &object2 != &*(new A()).
B object2 = *(new B());
We have lost the pointer to the allocated memory, and thus we cannot free it. delete &object2; may seem like it would work, but because &object2 != &*(new A()), it is not equivalent to delete (new A()) and so invalid.
In C# and Java, you use new to create an instance of any class and then you do not need to worry about destroying it later.
C++ also has a keyword "new" which creates an object but unlike in Java or C#, it is not the only way to create an object.
C++ has two mechanisms to create an object:
automatic
dynamic
With automatic creation you create the object in a scoped environment:
- in a function or
- as a member of a class (or struct).
In a function you would create it this way:
int func()
{
A a;
B b( 1, 2 );
}
Within a class you would normally create it this way:
class A
{
B b;
public:
A();
};
A::A() :
b( 1, 2 )
{
}
In the first case, the objects are destroyed automatically when the scope block is exited. This could be a function or a scope-block within a function.
In the latter case the object b is destroyed together with the instance of A in which it is a member.
Objects are allocated with new when you need to control the lifetime of the object and then it requires delete to destroy it. With the technique known as RAII, you take care of the deletion of the object at the point you create it by putting it within an automatic object, and wait for that automatic object's destructor to take effect.
One such object is a shared_ptr which will invoke a "deleter" logic but only when all the instances of the shared_ptr that are sharing the object are destroyed.
In general, whilst your code may have many calls to new, you should have limited calls to delete and should always make sure these are called from destructors or "deleter" objects that are put into smart-pointers.
Your destructors should also never throw exceptions.
If you do this, you will have few memory leaks.
B object2 = *(new B());
This line is the cause of the leak. Let's pick this apart a bit..
object2 is a variable of type B, stored at say address 1 (Yes, I'm picking arbitrary numbers here). On the right side, you've asked for a new B, or a pointer to an object of type B. The program gladly gives this to you and assigns your new B to address 2 and also creates a pointer in address 3. Now, the only way to access the data in address 2 is via the pointer in address 3. Next, you dereferenced the pointer using * to get the data that the pointer is pointing to (the data in address 2). This effectively creates a copy of that data and assigns it to object2, assigned in address 1. Remember, it's a COPY, not the original.
Now, here's the problem:
You never actually stored that pointer anywhere you can use it! Once this assignment is finished, the pointer (memory in address3, which you used to access address2) is out of scope and beyond your reach! You can no longer call delete on it and therefore cannot clean up the memory in address2. What you are left with is a copy of the data from address2 in address1. Two of the same things sitting in memory. One you can access, the other you can't (because you lost the path to it). That's why this is a memory leak.
I would suggest coming from your C# background that you read up a lot on how pointers in C++ work. They are an advanced topic and can take some time to grasp, but their use will be invaluable to you.
Well, you create a memory leak if you don't at some point free the memory you've allocated using the new operator by passing a pointer to that memory to the delete operator.
In your two cases above:
A *object1 = new A();
Here you aren't using delete to free the memory, so if and when your object1 pointer goes out of scope, you'll have a memory leak, because you'll have lost the pointer and so can't use the delete operator on it.
And here
B object2 = *(new B());
you are discarding the pointer returned by new B(), and so can never pass that pointer to delete for the memory to be freed. Hence another memory leak.
If it makes it easier, think of computer memory as being like a hotel and programs are customers who hire rooms when they need them.
The way this hotel works is that you book a room and tell the porter when you are leaving.
If you program books a room and leaves without telling the porter the porter will think that the room is still is use and will not let anyone else use it. In this case there is a room leak.
If your program allocates memory and does not delete it (it merely stops using it) then the computer thinks that the memory is still in use and will not allow anyone else to use it. This is a memory leak.
This is not an exact analogy but it might help.
When creating object2 you're creating a copy of the object you created with new, but you're also losing the (never assigned) pointer (so there's no way to delete it later on). To avoid this, you'd have to make object2 a reference.
It's this line that is immediately leaking:
B object2 = *(new B());
Here you are creating a new B object on the heap, then creating a copy on the stack. The one that has been allocated on the heap can no longer be accessed and hence the leak.
This line is not immediately leaky:
A *object1 = new A();
There would be a leak if you never deleted object1 though.
This is not exactly my code but it looks a lot like it
I have 2 tables of type CTable. They work in the same way as normal arrays but can be allocated dynamically and resized. So lets just pretend that they are arrays right now
One table has object references
MyObj obj1;
MyObj obj2;
MyObj table1[10];
table1[0] = obj1;
table1[1] = obj2;
Now because I want to order them differently sometimes, I've put pointers to these objects in another table
MyObj *table2[10];
table2[0] = &table1[0];
table2[1] = &table1[1];
Is there a way to get a reference to obj1 and obj2 through table2 so those object will get out of scope at the end of some kind of delete function
something like
void free() {
MyObj &obj = *table2[0];
}
and then bang, at the end of free, obj is delete automagically. Also, some kind of way to delete these objects through table2 would be acceptable.
If you want to control the objects' lifetime, you'll need to allocate them dynamically. In that case, your code would look something like this:
vect2.push_back(new MyObj);
vect2.push_back(new MyObj);
void func() {
MyObj &obj = *vect2[0];
// ...
vect2.erase(vect2.begin());
delete &obj;
}
In your case it good to be a one vector with just only pointers.
If it doesn't fits try this:
for(UINT i=0;i<vect1.size();++i)
{
MyObj * p = &vect1[i];
vect2.push_back(p);
}
// This is example of adding
P.S.
vector<MyObj*> vect2;
vect2.push_back(&obj1);
vect2.push_back(&obj2);
this code is wrong