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.
Related
vector<int>* v = new vector<int>;
for (int i = 0; i < 100; i++) {
(*v).push_back(i);
}
delete v;
Do I delete every element of the vector and free the memory? If not how do I free the memory?
An allocating new expression allocates memory, constructs a dynamic object into that memory, and returns a pointer to that object. When you pass such pointer to delete, the pointed object is destroyed and the memory is deallocated.
When an instance of a class, such as a vector is destroyed, its destructor is called. The destructor of vector destroys all elements of the vector.
Sidenote 1: It's rarely useful to use allocating new and delete. When you need dynamic storage, prefer to use RAII constructs such as containers and smart pointers instead.
Sidenote 2: You should avoid unnecessary use of dynamic memory in general. It's quite rare to need singular dynamic vector such as in your example. I recommend following instead:
std::vector<int> v(100);
std::ranges::iota(v, 0);
Sidenote 3: Avoid using (*v).push_back. It's hard to read. Prefer using the indirecting member access operator aka the arrow operator instead: v->push_back
I am under the assumption that the code bellow is a unique_ptr to an array (aka not what I want)
std::unique_ptr<int[]> arr;
arr = std::make_unique<int[]> (5);
arr[0] = *new int(1);
delete &arr[0]; // malloc error, want to avoid "delete"
However, I want an array that holds unique_ptrs like so...
std::unique_ptr<int> arr2 []; //Error, requires explicit size
arr2 = std::make_unique<int> [5]; //Desirable, does not compile
arr2[0] = std::make_unique<int>(1); //Desirable, does not compile
How do I go about making an array of unique_ptrs? If that is not possible, then how do I deal with a malloc error?
Do you want an array that holds unique_ptrs (as in the title), or a unique_ptr holding an array (as in your examples)?
If an array of unique_ptrs is what you want, then
std::vector<std::unique_ptr<int>>
or
std::array<std::unique_ptr<int>, 3>;
(for example) will do the job.
If a unique_ptr holding an array is what you're after, then unique_ptr<int[]> will work (there is a partial specialisation of unique_ptr to support it), although you can't use std::make_unique and will need to call operator new[] yourself:
std::unique_ptr<int[]> p{new int[42]};
However, if you think you need this, what you most likely really want is std::vector, and I'd strongly recommend using that instead.
Short answer: use vectors. They are much easier to work with and you don't have to explicidly allocate memory. You should also use typedefs for syntax simplicity.
typedef unique_ptr<int> intPtr;
vector<intPtr> vec;
vec.push_back(make_unique<int>(69));
auto myIntPtr = make_unique<int>(16);
vec.push_back(move(myIntPtr)); // unique ptrs cannot be copied, must be moved
unique_ptr<int[5]> p1; // valid syntax
std::unique_ptr<int[]> arr;
arr = std::make_unique<int[]> (5);
At this point you have a unique_ptr to an array of int. This sounds like it is exactly what you want.
arr[0] = *new int(1);
But this is questionable. It dynamically allocates a single int, assigns 1 to the allocated int, then it assigns the value, 1, at the allocated int into the array at element 0. the allocated int is left hanging with nothing pointing at it, and is now exceptionally difficult to `delete. This is a memory leak.
delete &arr[0]; // malloc error, want to avoid "delete"
And as you've seen, this is fatal. Rather than attempting to delete the leaked int, delete has been invoked with a pointer to the array stored in the unique_ptr. Eventually the unique_ptrwill try todelete` the array and fail because it's already gone.
Based on comments, OP intends
std::unique_ptr<int*[]> arr;
arr = std::make_unique<int*[]> (5);
arr[0] = new int(1);
delete arr[0];
But I'd like to talk them out of this idea. Let's look at their end goal: a templated class
template <class TYPE>
class MyVector
{
std::unique_ptr<TYPE[]> arr; // array of whatever type
public:
MyVector(size_t size): arr(std::make_unique<TYPE[]> (size))
{
}
TYPE& operator[](size_t index)
{
return arr[index];
}
// note the complete lack of growing, shrinking and other vector goodness
// as they are not needed for this example.
};
We can use this class with just about anything.
int main()
{
// vector of int
MyVector<int> vec(5);
vec[0] = 1;
// vector of pointer to int (yuck)
MyVector<int*> vec2(5);
vec2[0] = new int(1);
delete vec2[0];
// vector of smart pointer to int (also yuck, but less yuck)
MyVector<std::unique_ptr<int>> vec3(5);
vec3[0] = std::make_unique<int>(1);
// vector of std::string
MyVector<std::string> vec4(5);
vec4[0] = "I am the very model of a modern major general...";
}
If the user of the vector want it to contain pointers, they can say so. There is no reason to force the user to use a pointer.
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;
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;
}
Why this code does not cause memory leaks?
int iterCount = 1000;
int sizeBig = 100000;
for (int i = 0; i < iterCount; i++)
{
std::auto_ptr<char> buffer(new char[sizeBig]);
}
WinXP sp2, Compiler : BCB.05.03
Because you're (un)lucky. auto_ptr calls delete, not delete []. This is undefined behavior.
Try doing something like this and see if you get as lucky:
struct Foo
{
char *bar;
Foo(void) : bar(new char[100]) { }
~Foo(void) { delete [] bar; }
}
int iterCount = 1000;
int sizeBig = 100000;
for (int i = 0; i < iterCount; i++)
{
std::auto_ptr<Foo> buffer(new Foo[sizeBig]);
}
The idea here is that your destructor for Foo will not be called.
The reason is something like this: When you say delete[] p, the implementation of delete[] is suppose to go to each element in the array, call its destructor, then free the memory pointed to by p. Similarly, delete p is suppose to call the destructor on p, then free the memory.
char's don't have a destructor, so it's just going to delete the memory pointed to by p. In my code above, it is not going to destruct each element in the array (because it's not calling delete[]), so some Foo's will leave their local bar variable un-deleted.
The auto_ptr will only live for the duration of the loop iteration and will release the object connected to it on iteration completion.
The compiler can see that in this case new[] can allocate space in the same way as new - without storing the number of elements anywhere since there's no need to call trivial char destructors - and that's why later when delete is called by the auto_ptr's destructor instead of delete[] it causes no problems since the memory block has actually been allocated in the new's way and that allocation can be paired with delete.
This is an example of a thing not to do. It's up to the compiler to decide whether to replace new[] with new. Using delete instead of delete[] and vice versa is undefined behaviour.
See Why would you write something like this? (intentionally not using delete [] on an array) for discussion of delete vs delete[].