While I understand that this is probably not the best of ideas, I ask hypothetically:
Is it legal to (i.e. defined behavior) to invoke an object's
destructor manually, and then reuse the memory for another object?
Definitions:
class A {
int a, b, c;
A() {}
~A() {}
}
A createObject() {
A object;
return object;
}
Code:
A* object = new A();
// Use object...
object->~A();
*object = createObject();
You can't call the assignment operator on a destroyed object like you are doing. At least not generally, though it might work with some types. What you can do is this though:
A* object = new A();
object->~A();
// Placement new.
// Constructs a new object in the memory pointed to by object pointer.
// Doesn't allocate memory.
new (object) A(createObject());
You can even use placement new to construct objects of a different type in that memory, as long as they fit. Just be sure of two things:
Don't ever construct an object on top of an already existing object that has not been destructed.
Don't ever call delete on a pointer after you've called the destructor on the object it points to until you've re-construced an object (of the same type) in its place.
Calling a destructor explicitly is a legal thing to do - in fact, that's what you do when you use placement new. Initializing an object "in place", when the memory is already allocated, is also a legal thing do do, but you should do it differently: rather than using the assignment operator, you could use this syntax:
object = new (object) A(); // Placement syntax
The way you did it (with an assignment operator) is incorrect, because you are calling a function (i.e. the assignment operator) on an object the destructor of which has completed.
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 codes to dynamically allocate a class object in a function call:
#include <iostream>
class A
{
public:
A(){std::cout<<"Constructing..."<<std::endl;}
~A(){std::cout<<"Deconstructing..."<<std::endl;}
};
A & f()
{
std::cout<<"Calling f()"<<std::endl;
A * pa = new A();
std::cout<<"End calling f()"<<std::endl;
return *pa;
}
int main()
{
A & b = f();
}
The output are:
Calling f()
Constructing...
End calling f()
which means that the class object was never deleted.
However, if I change the line in main to:
A b = f();
the outputs are:
Calling f()
Constructing...
End calling f()
Deconstructing...
which means the class object was deleted automatically.
Why that assigning a reference to a non-reference will change its dynamic behavior?
There's no change to the dynamic object created by new. That's not destroyed in either case, since it can only be destroyed by explicit use of delete.
In the second case, you create a second object b by copying the dynamic object. Being automatic, that is destroyed when it goes out of scope, so you see a Deconstructing... message from that.
Since it was initialised by a copy constructor, not the default constructor, you don't see a corresponding Constructing... message. You could add a copy constructor to see that:
A(A const &){std::cout<<"Copying..."<<std::endl;}
giving the output
Calling f()
Constructing...
End calling f()
Copying...
Deconstructing...
In general, always use smart pointers and other RAII types to manage dynamic resources, to avoid memory leaks and other lifetime confusion issues.
In the case of
A & b = f();
b refers to the object created on the heap.
In the case of
A b = f();
b creates a copy (possible move) of the data on the heap. This one is destructed when the function exits (when b goes out of scope).
The object on the heap is left alone, in both cases.
To explore this further, the addition of the copy constructor would help A(A const&) and then printed a message, or even making it private and noting the compilation errors aid in marking the copies and their locations.
Note: when you new an object in a function and then don't destroy it, or don't move the pointer to some other owner, you will leak memory. Favour library utilities like unique_ptr or share_ptr to manage the resource (RAII).
When you declare a value type, it is constructed on the stack and the compiler takes care of calling its destructor when it goes out of scope. However, when you create the instance on the heap by calling new, the compiler can't know when the instance is not needed any more and therefor it's up to the programmer to indirectly call its destructor by using delete. The fact that you have a reference to the object on the heap doesn't provide the compiler with any knowledge of when the object has to be destroyed.
When I create an object of a class, say,
class A {
public: A() {}
};
A a;
Is only the constructor called? Or is it that the new operator is used implicitly?
Like we have to do A* b = new A();
Also, where will a and b be stored in memory? Stack or heap?
In the first case, if a is not a global variable, then it will be put on the stack, while b will be put on the heap.
And in the first case, only the constructor is called. new is never called except if you do it explicitly as in the second case.
No new is not called implicitly. new returns a pointer to the type of object created whereas a constructor call does not have a return type. Objects created with new will exist on the heap. New will allocate memory, then call the constructor. Objects created in the form A a will exist on the stack (unless they are global variables).
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 question might be silly, but I want to know, if a copy constructor is invoked when a pointer to an object is returned by a function?
Also,consider following:
A* a1 = new A();
A* a = a1.GetPointer();
A* GetPoineter()
{
.....
return new A();
}
so does
A* a = a1.GetPointer();
call copy constructor?
also if I delete a, will it delete the address pointed by a1 also?
No, it does not call the copy constructor since you are returning the address of the object, not the object itself.
delete a; will only delete the object allocated in the GetPoineter function. a1 is untouched since it points to a completely different object.
so does A* a = a1.GetPointer(); calls copy constructor?
No.
In your case you are not returning an object but just address of an object so it does not result in copy constructor call.
In case when you are returning Objects, It depends on the compiler.
Modern day compilers are smart enough to prevent the additional call to copy constructor by using Return Value Optimization(RVO) and Named Return Value Optimization(NRVO).
Also i I delete a, will it delete the address pointed by a1 also?
No it won't.
If you just delete a then your code will result in memory leak, because you still did not deallocate memory allocated to a1. Both have been explicitly allocated dynamic memory separately, So both must be deallocated separately.