Consider the following example:
#include <vector>
class Foo {
std::vector<int*> v;
public:
Foo() {
this->v.push_back(new int(23));
this->v.push_back(new int(24));
this->v.push_back(new int(25));
}
~Foo() {
}
};
int main() {
Foo f;
return 0;
}
When f goes out of scope in main(), f's destructor is called, which should indirectly free f.v. According to this, the destructor of each element of the vector v should now be called.
However, when I run this program in valgrind, I find that the int*'s were not deallocated.
$ valgrind --leak-check=full ./a.out
What am I missing here?
std::vector<T> does indeed call the destructor of T when it is destroyed. Here T is int *. The destructor of int * does nothing. The storage for the int * itself is freed, but the ints they point to are not.
Consider:
int main() {
int *x = new int(23);
return 0;
}
This exhibits the same problem; when x goes out of scope, its destructor is indeed called, and the storage for the pointer that is x is freed, but since the destructor of a pointer is a no-op, the pointed-to int is not freed.
More to the point, vector doesn't know how the ints were allocated. They might be allocated by new int, but they could also point to elements inside an array allocated with new int[200], or they might point to malloc'd data, or they might point into a mmap'd buffer, or they might point to struct elements, or two vectors might be pointing to the same ints... etc. vector isn't smart enough to divine what you want done with these, and so it leaves them alone (additionally, giving vector logic to delete pointed-to elements would break vectors of non-pointer elements such as std::vector<int>, as you can't delete an int!)
You need to either use a std::vector<int>, or use a smart pointer in conjunction with it, eg std::vector<boost::shared_ptr<int> >. Note that using smart pointers may add overhead; with C++0x you should be able to use std::vector<std::unique_ptr<int>> in conjunction with std::move to avoid this overhead. Boost also has pointer vectors that free the pointed-to elements as you expected as well.
The destructor of each element of the vector v should now be called
Yes: the int* objects stored in the vector are destroyed (which is effectively a no-op). The objects pointed to by the pointers in the container are not destroyed.
Consider the following, equally valid program:
{
int x;
std::vector<int*> v;
v.push_back(&x);
} // x cannot be delete'd because it isn't dynamically allocated.
You should use a smart pointer, like std::unique_ptr or shared_ptr so that you don't have to worry about the memory management (do not use std::auto_ptr; it is incompatible with the Standard Library containers because it isn't really copyable). If you don't use a smart pointer then you need to destroy the dynamically objects yourself; doing this correctly is rather difficult.
Each element of your vector is an int *. When an int * is destroyed, the language does not automatically call delete on it. In other words, it's the pointer being destroyed, not the pointee.
Since you are using the new keyword, the integers are being allocated on the heap rather than the stack. In other words, they are being allocated dynamically. In other words, you need to clean up after it.
The "destructor" for a pointer type is to simply delete that pointer. It does not touch the data which is located at the memory address stored by the pointer. Consider the following example:
int a = 5;
int* i = &a;
if (true)
{
int* j = i;
} //j goes out of scope, should *i and a be deleted? no.
So you will need to do this in the destructor:
std::vector<int*>::iterator iter;
for (iter = v.begin(); iter != v.end(); iter++)
{
delete *iter;
}
Related
I want to create some continuous memory, and use bunch of shared_ptr pointing to them.
int main() {
int *arr = new int[5];
for (int i = 0; i < 5; i++) {
std::shared_ptr<int> ptr(&arr[i]);
}// when the loop scope end, the shared_ptr will be destroyed.
};
this code will give an error:
pointer being freed was not allocated
my expectation: when the scope of loop end, the shared_ptr will be destroy, and the element in array will be destroyed successively.
But it seems that when the first pointer is destroyed, the whole array is freed.
I also tried std::allocator, still not work.
So is there any way that can allocate continuous memory, and I can use shared_ptr pointing to each of them, then when the first element is freed, the whole memory won't be freed together?
Its an "interesting" thing to want to do but if you really want to do it you can use the shared_ptr's aliasing constructor.
int main() {
std::shared_ptr<int[]> arr(new int[5]);
for (int i = 0; i < 5; i++) {
std::shared_ptr<int> ptr(arr,&arr[i]);
}
};
Without c++17 you need to do a little more:
int main() {
std::shared_ptr<int[]> arr(new int[5], std::default_delete<int[]> {});
for (int i = 0; i < 5; i++) {
std::shared_ptr<int> ptr(arr, &arr.get()[i]);
}
};
The array will be deleted when the last element shared_ptr is destroyed (assuming the array shared_ptr itself has already been destroyed/reset).
You are misusing shared_ptr. The memory you allocated was attributed with operator new[], it should thus be freed with operator delete[].
Furthermore, since the allocated object is an array, any ownership semantics should be applied to the whole array and not divided across its elements!
You can achieve by specifying a custom deleter for your shared_ptr: (C++11/14)
std::shared_ptr<int> arr_ptr(new int[5], std::default_delete<int[]> {});
Or simply using an array type specialization of shared_ptr (C++17):
std::shared_ptr<int[]> arr_ptr(new int[5]); // Will call delete[] upon destruction.
I was thinking about a this situation not for a real implementation but to understand better how pointers works.
class foo(){
foo();
~foo();
void doComplexThings(const std::vector<int*>& v){
int* copy;
for(int i = 0; i < v.size(); i++){
copy = v[i];
// do some stuffs
}
}
}
main(){
std::vector<int*> myVector; // suppose we have 100 elements
doComplexThings(myVector);
for(int i = 0; i < myVector.size(); i++){
delete myVector[i];
}
myVector.clear();
}
Ok, I know that have no sense to copy v[i] inside an other pointer, but I was thinking: copy do a memory leak?
After the execution of doComplexThings(), copy will continue to exist and will occupy space in the heap?
After deleting all elements it will continue to exist and point to a deallocated memory?
So logically if I do this things with complex objects I'll keep occupy the memory with unreference object? Or copy is saved in the stack because I don't use new? And at the end of doComplexThings it will be deleted?
I'm a bit confused, thanks!
There is some confusion on the topic of pointers in the C++ community. While it is true that smart pointers have been added to the library to alleviate problems with dynamic memory allocation, raw pointers are not obsolete. In fact, whenever you want to inspect another object without owning it, you should use a reference or raw pointer, depending on which suits your needs. If the concept of ownership is unclear to you, think of an object as being owned by another object if the latter is responsible for cleaning up afterwards (deleting the former).
For example most uses of new and delete should be replaces with the following (omitting std for brevity):
{
auto ptr_to_T = make_unique<T>(//constructor params);
do_stuff_with_smart_ptr(ptr_to_T);
do_stuff_with_T(*ptr_to_T);
do_stuff_with_raw_ptr(ptr_to_T.get());
} // automatic release of memory allocated with make_unique()
Notice how a function that takes a T* doesn't need a smart pointer if it doesn't keep a copy of the T* it is given, because it doesn't affect the lifetime of the object. The object is guaranteed to be alive past the return point of do_stuff_with_T() and its function signature signals that it doesn't own the object by taking a raw pointer.
On the other hand, if you need to pass the pointer to an object that is allowed to keep the pointer and reference it later, it is unclear when the object will need to be destroyed and most importantly by whom. This is solved via a shared pointer.
ClassThatNeedsSharedOwnership shared_owner;
{
auto ptr_to_T = make_shared<T>(//constructor params);
shared_owner.set_T(ptr_to_T);
// do a lot of stuff
}
// At this point ptr_to_T is destroyed, but shared_owner might keep the object alive
So how does the above factor in to your code. First of all, if the vector is supposed to own (keep alive) the ints it points to, it needs to hold unique_ptr<int> or shared_ptr<int>. If it is just pointing to ints held by something else, and they are guaranteed to be alive until after the vector is destroyed, you are fine with int*. In this case, it should be evident that a delete is never necessary, because by definition your vector and the function working on the vector are not responsible for cleaning-up!
Finally, you can make your code more readable by changing the loop to this (C++11 which you've tagged in the post):
for (auto copy : v){
// equivalent to your i-indexed loop with copy = v[i];
// as long as you don't need the value of i
do_stuff_to_int_ptr(copy);
// no delete, we don't own the pointee
}
Again this is only true if some other object holds the ints and releases them, or they are on the stack but guaranteed to be alive for the whole lifetime of vector<int*> that points to them.
No additional memory is allocated on the heap when you do this:
copy = v[i];
variable copy points to the same address as v[i], but no additional array is allocated, so there would be no memory leak.
A better way of dealing with the situation is to avoid raw pointers in favor of C++ smart pointers or containers:
std::vector<std::vector<int>> myVector;
Now you can remove the deletion loop, which is an incorrect way of doing it for arrays allocated with new int[length] - it should use delete[] instead:
delete[] myVector[i];
Basically you're illustrating the problem with C pointers which lead to the introduction of C++ unique and shared pointers. If you pass a vector of allocated pointers to an opaque member function, you've no way of knowing whether that function hangs onto them or not, so you don't know whether to delete the pointer. In fact in your example you don't seem to, "copy" goes out of scope.
The real answer is that you should only seldom use allocated pointers in C++ at all. The stl vector will serve as a safer, easier to use version of malloc / new. Then you should pass them about as const & to prevent functions from changing them. If you do need an allocated pointer, make one unique_ptr() and then you know that the unique_ptr() is the "owner" of the memory.
I am converting a vector of doubles to an array of doubles as seen here:
The difference is, that I want to return the pointer a as a function parameter:
void getArray(double* a)
{
std::vector<double> v;
a = &v[0];
}
So my question is, when does the memory of a gets deallocated? Or do I have to call delete[] a by myself, which seems strange since I did't allocate the memory with new. I have read the comments to the above mentioned answer but it still isn't clear to me.
The memory pointed to by a gets deallocated when the vector v is destructed. In this case, that's at the end of the function getArray.
This implementation would invoke undefined behavior because v is local:
void getArray(double* a)
{
std::vector<double> v;
a = &v[0]; // would be a UB for returning the pointer to internals of a local variable.
}
However, the caller will never see any effect of this, because modifications to a stay local to getArray function.
If you want to make an array out of a vector, allocate a new array, use std::copy to copy the content into it, and return the array to the caller. Make sure the callers call delete[] on the result once they are done with the copyL
double *getArray(const vector<double>& v) {
double *res = new double[v.size()];
std::copy(v.begin(), v.end(), res);
return res;
}
The caller should use it as follows:
vector<double> data;
data.push_back(...);
... // populate the vector
double *tmp = getArray(data);
... // Use the array
delete[] tmp; // Avoid memory leaks
Don't do this:
void getArray(double* a)
{
std::vector<double> v;
a = &v[0];
} // The vector is destroyed here, and the memory
// is deallocated.
In any case, you're not modifying the a pointer outside of your function, so you won't get the desired effect.
Instead, return the vector and use it directly. Or, in general, use vectors throughout your code. If you need to pass them in to a function that expects a pointer to an array, you can pass &v[0] there. Such a function usually expects the size too. For this, pass v.size(). You can do this safely as long as that function doesn't take ownership, or deallocate the memory.
Note, also, that a vector declared as std::vector<double> v; does not have a size, so attempting to access the first element, as in v[0] is also undefined behaviour. At the very least, you need to give the vector a size (pass a size to its constructor) to ensure some memory is allocated. You should always make sure the vector has some allocated memory before indexing into it, including when trying to take the address of the first element.
What you probably want to do is:
std::vector<double> getArray() {
std::vector<double> v = /* some sane initialisation */;
return v;
}
// some time later, assuming a function:
// void do_something(double* a, size_t n);
// ...
std::vector<double> v = getArray();
if (v.size()) {
do_something(&v[0], v.size());
} else {
// fail gracefully
}
when does the memory of a gets deallocated?
The a pointer itself is a local variable, so it is deallocated at the end of its scope.
a points to the memory allocated by the vector v. The pointed memory is deallocated in the destructor of v (The memory may also be deallocated if objects are added to or removed from the vector). And because v is a local variable, it is destroyed at the end of scope.
Or do I have to call delete[] a by myself,
No, because the memory is owned by the vector object, but also because
which seems strange since I did't allocate the memory with new.
Exactly. You didn't call new[], so you don't call delete[].
Note that v[0] has undefined behaviour because the vector is empty.
I have been pondering an issue today and it's difficult to find the answer on google.
I'm trying to understand the STL container behaviour when dealing with pointers to both objects allocated on the heap, and on the stack.
So, start with objects, no pointers ... imagine I have ...
std::vector<int> myVec;
while(true)
{
int myInt = 5;
myVec.push_back(myInt);
myVec.pop_back();
}
My understanding is that the pop_back() method will ensure the integers contained in the vector are deleted, not just removed from the container. So if this ran and did a billion iterations, I should not expect to leak memory. Everything I insert, will be deleted. A memory check shows this behaviour.
Now consider I use a vector of pointers (to objects on the heap) ...
std::vector<int*> myVec;
while(true)
{
int * myIntP = new int(5);
myVec.push_back(myIntP);
myVec.pop_back();
}
In this case, only the pointer itself ought to be removed each time pop_back() is called, and the underlying object remains un-deleted, causing a memory leak. So after a billion iterations I have quite some significant memory being used, even though I have no entries in my vector.
Now what if I have a vector of pointers (to objects on the stack) ...
std::vector<int*> myVec;
while(true)
{
int myInt = 5;
int * myIntP = &myInt;
myVec.push_back(myIntP);
myVec.pop_back();
}
Here the pointers point to stack objects. Is their memory freed in the call to pop_back(), or not? A memory check showed me that this behaviour was no memory leaked. The small amount of memory used, indicated that this behaved like objects on the stack. However this was not expected to me, because if the pointer had been passed into me from another function, to a stack variable i.e.
void myFunc(int * myIntP)
{
std::vector<int*> myVec;
myVec.push_back(myIntP);
myVec.pop_back();
}
int main()
{
int myInt = 5;
int * myIntP = &myInt;
myFunc(myIntP);
std::cout << (*myIntP) << std::endl;
return 0;
}
Then allowing the vector to free this memory, would render my myIntP pointing to removed data. So surely this can't be correct?
Could anyone help explain?
Also is there a name for "a pointer pointing to a variable on the stack" i.e. not initialised with "new"?
Thanks
Joey
while(true)
{
int myInt = 5;
int * myIntP = &myInt;
myVec.push_back(myIntP);
myVec.pop_back();
}
You only actually have one int here, myInt with a value of 5. The loop will re-use the same one. You push a pointer to that one int into the vector and then remove it. Nothing else is happening. There isn't a memory leak because you are not allocating new ints.
STD containers do nothing different for pointers than they would for a 32/64 bit interger. As far as they care, a pointer is just another number. So, if you insert a pointer into a container, it is your responsibility to delete it.
If you make a pointer to a variable on the stack, the variable will be destructed when it goes out of scope, regardless of the pointer. And destructing the pointer (as long as you don't call delete on it) will have no effect on the variable.
So if you stop using your pointer before, no problem, if you store it longer, problem...
And if you plan on using pointers on dynamically allocated variable, you should look into smart pointers.
Here the pointers point to stack objects. Is their memory freed in the call to pop_back(), or not?
No, they are not. They are freed when they go out of scope, which happens at the }. After the }, the memory is no longer used for this variable (the stack-frame popped off) and will be reused! So if you didn't pop-off the pointer right after pushing it, your vector would contain a dangling pointer when the variable goes out of scope.
So, let's go through each of your examples:
std::vector<int> myVec;
while(true)
{
int myInt = 5;
myVec.push_back(myInt);
myVec.pop_back();
}
The push_back() method makes a copy of the argument and stores the copy internally. So, if you were storing an stack-allocated object instead of a primitive, a copy constructor would have been called. The pop_back() method does not assume anything either. It removes the copy of the item you stored (whether it was a value or a pointer) and removes it from its internal storage. If the copy stored was a stack-allocated object, the class' destructor will be called when the container manages its internal memory because the copy item will no longer be in scope.
Your second example:
std::vector<int*> myVec;
while(true)
{
int * myIntP = new int(5);
myVec.push_back(myIntP);
myVec.pop_back();
}
As you stated, the integer is allocated on the heap. Calling push_back() still stores the argument. In this case, you are not storing the value of the integer "5", the value of the pointer, an address of a memory location that contains the value of "5". Since you allocated the memory that stores the "5", you are responsible for getting that pointer and deallocate the memory. The pop_back() method does not delete the pointer for you nor returns you a copy of the pointer.
Your third example has subtle differences:
std::vector<int*> myVec;
while(true)
{
int myInt = 5;
int * myIntP = &myInt;
myVec.push_back(myIntP);
myVec.pop_back();
}
In this case, you are not allocating any memory on the heap. You assigning the address of myInt, which is a stack-allocated value, to a pointer. Stack memory lives through out the life of a process and does not deallocate on its own. However, once you leave the current scope (the while loop), the memory reused by something else. The memory is still there, but it may no longer have the value you expect.
Your last example:
void myFunc(int * myIntP)
{
std::vector<int*> myVec;
myVec.push_back(myIntP);
myVec.pop_back();
}
int main()
{
int myInt = 5;
int * myIntP = &myInt;
myFunc(myIntP);
std::cout << (*myIntP) << std::endl;
return 0;
}
You were expected the memory for myInt to be dealloated after making myFunc() was called. However, container methods do not modify the supplied values. They copy them. When myFunc() pushed the myIntP pointer, it is pushing the pointer, the address of what myIntP points to, not the value in memory of that address. You would have to dereference the pointer, using call:
myVec.push_back(*myIntP);
Note that even if you did this, containers copy the value. So, myInt is still unaffected.
You are confusing and conflating "destruction" and "deletion" -- they are NOT the same thing, but are two different concepts in C++.
Deletion can only happen with pointers -- if you try to delete a non-pointer, you'll get a compile-time error. Deletion first destroys the pointed at object and then returns the memory for it to the heap.
Destruction on the other hand can happen with anything, but is mostly only of interest with classes, where it calls the destructor. With any type that has no destructor (such as int or any raw pointer type), destruction does nothing. While you CAN destroy an object manually, you pretty much never do -- it happens automatically for you when something else happens. For example, when a local variable goes out of scope, it is destroyed.
So in your code above, what happens? Well you have a local std::vector which is destroyed when it goes out of scope. Its destructor will delete anything it allocated internally, and destroy all the elements of the vector. It will NOT however, delete any elements of the vector. When you have vector<int>, that's all there is, since nothing else was allocated, but when you have a vector<int *>, if those pointers were allocated, they'll leak. If they weren't allocated (if they point at locals), there's nothing to leak.
I think you need to learn deep the scope variable validity
exemple :
{
int myVar;//Construct myVar on the stack
}//At this point, myVar is deleted with the stack
in your last exemple, you declare myInt at the start of main and don't do anything on value in myFunc.
It's normal to don't lose myInt data. it will be erase after the return 0;
vector< int > vect;
int *int_ptr = new int(10);
vect.push_back( *int_ptr );
I under stand that every "new" needs to be followed by a "delete" at some point but does the clear() method clean this memory?
What about this method of doing the same thing:
vector< int > vect;
int int_var = 10;
vect.push_back( int_var );
From what I understand, clear() calls the variables destructors, but both vect.push_back() methods in this example push an object on the vector, not a pointer. so does the first example using an int pointer need something other than clear() to clean up memory?
The first method leaks because the vector never takes ownership of the allocated pointer. In fact, it doesn't contain a pointer at all, only a copy of the value.
The second method does not leak, as no memory is dynamically allocated (except internally in the vector -- it will handle that memory itself).
When you push_back on a vector, you add a copy of the data to the vector. Therefore, in both cases, the original data still needs to be freed. In the first case, you need to delete it; in the second, it will be "freed" by the stack pointer as it goes out of scope.
Vectors make copies on push_back. Since a pointer is 'just another variable' (but one that happens to point to memory), when you push_back an integer pointer that has been previously allocated, you copy the pointer's value into the vector, causing a potential dangling pointer, since there will be two pointers pointing at the same spot in memory.
In your first example, you would need to delete the memory manually. One strategy I've used in the past for meddling with graph classes is to have something like this (vast amounts of stuff redacted due to being at work and typing quickly):
class graph //quick-format
{
vector<node*> nodes;
add_node(node n)
{
node *temp = new node;
*temp = n;
nodes.push_back(temp)
}
~graph()
{
for(int i = 0; i < nodes.size(); i++)
delete nodes[i];
}
};
As a caveat, graph's copy semantics will have to be examined. As it stands, it will result in deleting previously-free'd memory. The advantage is that you can always have the same set of nodes hanging around. Caveat Emptor, like any direct memory usage..
However, if you simply push a non-pointer variable, there is no possibility of memory leaking from your end. Possibly the vector will leak, but... that is practically impossible at this point in the maturity of the tools.