So let's say that you wanted to make a realloc function in C++. I imagine it can work something like this:
template<typename T>
void realloc(T** arr, int size, int original_size){
T *newArr = new T[size];
for(int i = 0; i<original_size;i++)
newArr[i] = (*arr)[i];
delete[] *arr;
*arr = newArr;
}
Now my question is wheter it is correct to use delete[] here? From what I know allocated memory size is tracked at runtime so C++ knows how much to delete. Is that preserved when passing it like this or are there better ways of doing this?
Now my question is wheter it is correct to use delete[] here?
Yes, as long as *arr was allocated using new[].
From what I know allocated memory size is tracked at runtime so C++ knows how much to delete. Is that preserved when passing it like this [...]?
I'm not really sure what you mean here. The runtime keeps track of memory allocations, yes. But you have to be explicit about using delete[] for arrays (like new int[10]) and delete for non-arrays (like new MyClass()).
or are there better ways of doing this?
Using raw pointers should be avoided, even naked new is considered bad practice these days. Smart pointers and STL-containers like std::vector are superior alternatives for almost every scenario.
Related
In C++ when we assign an array there is no way to find out the size of the array once it has been initialized. Then how does the delete operator know the amount of memory to delete when I am trying to deallocate memory at the end of my program.
int main()
{
int* p = new int[10];
int* q = new int[30];
//... bunch of code
//...
// ... bunch of code
delete[] p;
delete[] q;
return 0;
}
The new operator ends up creating an entry on the heap, and the heap allocator knows how to de-allocate things it's previously allocated. This information isn't normally available to your code because it's all C++ internals you're not supposed to mess with.
So basically the heap metadata describes this allocation.
Remember that in C++ you can write your own allocator, so new and delete[] might end up interfacing with that if you so desire. If you look at how std::allocator is defined, note that you're not obligated to tell anyone what allocations have been made, nor how big any particular allocation is. The allocator has a tremendous amount of freedom here, and the specification doesn't allow for a lot of interrogation.
If I have a function like:
void MyFunctoin(int size){
// ...
int *arr=new int[size];
// ...
}
Is there a memory leak?
If yes, is there a way to solve it without using delete?
The answer to your title question is simple: yes, every new must be matched by a delete. In your case, since you used new[], there must be a delete[] somewhere.
But you don't need to write it yourself. It is usually much better to use a class that manages its own resources. In your case, you'd be better off using an STL container such as array<> or vector<>. This is, either:
std::array<int, size> arr; // fixed size (known at compile time)
or
std::vector<int> arr; // variable size
In vector, all the necessary calls to new and delete are done inside the container and you needn't care about them.
You could write your function this way:
#include <vector>
void MyFunctoin(int size){
// ...
std::vector<int> arr(size);
// ...
}
and there would not be any memory leak with no need to call delete anywhere. You don't need to specify size when constructing arr if you don't want to.
Yes, it is. Use smart pointers/STL containers (for example std::vector/boost::shared_array/std::unique_ptr<T[]> in your case).
There is a leak if the ... part after the arr = new does not contain a delete [] arr, yes.
The solution is to either add a delete [] arr at a suitable point, or use vector<int> arr(size);, or unique_ptr<int[]> arr(new int[size]).
Which is the "right" choice really depends on what you are overall trying to achieve.
Yes. but you can use below smart pointer to get rid of that:
std::unique_ptr<int[]> arr (new int[size]);
Yes. You need to match up each new with a delete, and each new[] with a delete[].
There are two alternatives. The first is to use a garbage collecting library such as the well-known Boehm GC.
The second, better solution is to use smart pointers. These will call delete for you at the appropriate time. There are a couple in the C++ standard library, and Boost has lots more that cover just about every possible use-case.
As already pointed out, all news must have matching deletes somewhere. Smart pointers conveniently handle this for you.
Another, non-C++ solution that might apply here would be to not use new, but alloca from the standard C library. This is more lightweight and you don't have to deallocate, but of course you can blow up the stack if size gets too big.
yes.
use a smart pointer
template<class C> struct smartpointer
{
C* data;
smartpointer():data(NULL){}
~smartpointer(){if(data){delete data;data=NULL;}
};
this automatically destroy its content when the block expires
Is there a way to expand a dynamic memory array? like this:
int *a = new int[5];
*a = new int[2];
Is this legal?
You cannot expand this type of a dynamic memory array. You can use malloc and realloc though if you need this facility but I would advice against that and suggest including <vector> and using std::vector instead. It has a resize method.
Also, what you described won't compile. The following will:
1: int *a = new int[5];
2: a = new int[2];
The above will allocate two memory blocks, neither of which will be destroyed. Second line will simply assign a new array to the same int *a pointer. When an allocated memory stops being referenced by any pointer, this is called a memory leak. The above code loses any reference to new int[5] and there is no way to free this memory to the operating system.
Although this is not a very practical example, there are multiple ways to resize an array/vector.
As it is usually practical to increase the array size, I will do just this:
{ // C++ vector on the stack (although internally vector uses memory from the heap)
std::vector<int> a(1024);
// do smth
a.resize(4096); // note: this does not always reallocate
// do smth else
}
{ // C++ everything on the heap
std::vector<int> *a = new std::vector<int>(1024);
// do smth
a->resize(4096); // note: this does not always reallocate
// do smth else
delete a;
}
{ // C style
int *a = (int*)malloc(1024*sizeof(int));
// do smth
a = realloc(a, 4096*sizeof(int));
// do smth else
free(a);
}
It is worth to note that realloc does not do anything smart. All it does is:
Allocate new memory block malloc
Copy data from old memory block to new memory block memcpy
Free old memory block free
Return new memory block
You can certainly expand an array, but you need to take care of copying the contents and of freeing the old array (your code, apart from being incorrect syntax, shrinks the array, btw.).
Which is exactly how std::vector works, just you don't have to care.
So basically, having int *a already allocated, what needs to happen is something like:
{
std::unique_ptr<int[]> d(a);
a = new int[desired_new_size];
for(unsigned int i = 0; i < min_old_size_and_new_size; ++i)
a[i] = d[i];
}
Note that strictly speaking "expanding" never really expands the array, but replaces it with another bigger one (that is true for any containers offering the same functionality too). But this is transparent to any code using the pointer later, nobody will know.
You should never use realloc (or any other C memory allocation functions) in combination with memory allocated or freed by operator new and delete (or new[] and delete[]) as pointed out above.
This may work (and usually will), but it's conceptually wrong, and it's pure luck (unknown implementation detail) if it does not crash.
Having structs like
struct ifoo_version_42 {
int x, y, z;
char *imageData;
};
where imageData is something like imageData = new char[50000];
Can we perform something like:
template< typename T >
void del( T a ) // we promise to use this only on C Plain Old data structs=)
{
delete a;
}
on this structure an will it be enough to clean memory form if?
Deleting the struct does not recursively delete any pointers in it, and hence doesn't free the array of char pointed to by imageData.
I'm also a bit confused by your use of delete[]. You can free an array (allocated with new[]) using delete[], or free a single object (allocated with new) using delete. You can't mix them, and you don't say how you're allocating one or more instances of ifoo_version_42. For example the following has undefined behavior:
ifoo_version_42 *x = new ifoo_version_42;
del(x);
The following is OK:
ifoo_version_42 *x = new ifoo_version_42[1];
del(x);
This function template would also "work" on non-POD types. It's literally no different from invoking delete[] a; directly.
However, this won't delete the memory associated with imageData. That's typically the sort of thing you do in a destructor.
If you perform your del function on an ifoo_version_42, then the memory block pointed to by data will not be freed; neither delete nor delete[] work recursively.
delete[] is meant to be used for freeing arrays; that is, if you allocated imageData with new[], then it should be freed with delete[].
delete is meant to be used for freeing single objects: If you e.g. allocated a ifoo_version_42 with new, then you should free it with delete.
(Also, never use delete for something allocated with malloc(), or free() with something allocated with new.)
One further suggestion: Learn the RAII idiom and use smart pointer classes provided by the STL or Boost libraries; these go a long way towards helping you with correct memory management.
I come from a java background and there's something I could do in Java that I need to do in C++, but I'm not sure how to do it.
I need to declare an array, but at the moment I don't know the size. Once I know the size, then I set the size of the array. I java I would just do something like:
int [] array;
then
array = new int[someSize];
How do I do this in C++?
you want to use std::vector in most cases.
std::vector<int> array;
array.resize(someSize);
But if you insist on using new, then you have do to a bit more work than you do in Java.
int *array;
array = new int[someSize];
// then, later when you're done with array
delete [] array;
No c++ runtimes come with garbage collection by default, so the delete[] is required to avoid leaking memory. You can get the best of both worlds using a smart pointer type, but really, just use std::vector.
In C++ you can do:
int *array; // declare a pointer of type int.
array = new int[someSize]; // dynamically allocate memory using new
and once you are done using the memory..de-allocate it using delete as:
delete[]array;
Best way would be for you to use a std::vector. It does all you want and is easy to use and learn. Also, since this is C++, you should use a vector instead of an array. Here is an excellent reason as to why you should use a container class (a vector) instead of an array.
Vectors are dynamic in size and grow as you need them - just what you want.
The exact answer:
char * array = new char[64]; // 64-byte array
// New array
delete[] array;
array = new char[64];
std::vector is a much better choice in most cases, however. It does what you need without the manual delete and new commands.
As others have mentioned, std::vector is generally the way to go. The reason is that vector is very well understood, it's standardized across compilers and platforms, and above all it shields the programmer from the difficulties of manually managing memory. Moreover, vector elements are required to be allocated sequentially (i.e., vector elements A, B, C will appear in continuous memory in the same order as they were pushed into the vector). This should make the vector as cache-friendly as a regular dynamically allocated array.
While the same end result could definitely be accomplished by declaring a pointer to int and manually managing the memory, that would mean extra work:
Every time you need more memory, you must manually allocate it
You must be very careful to delete any previously allocated memory before assigning a new value to the pointer, lest you'll be stuck with huge memory leaks
Unlike std::vector, this approach is not RAII-friendly. Consider the following example:
void function()
{
int* array = new int[32];
char* somethingElse = new char[10];
// Do something useful.... No returns here, just one code path.
delete[] array;
delete[] somethingElse;
}
It looks safe and sound. But it isn't. What if, upon attempting to allocate 10 bytes for "somethingElse", the system runs out of memory? An exception of type std::bad_alloc will be thrown, which will start unwinding the stack looking for an exception handler, skipping the delete statements at the end of the function. You have a memory leak. That is but one of many reasons to avoid manually managing memory in C++. To remedy this (if you really, really want to), the Boost library provides a bunch of nice RAII wrappers, such as scoped_array and scoped_ptr.
use std::array when size is known at compile time otherwise use std::vector
#include <array>
constexpr int someSize = 10;
std::array<int, someSize> array;
or
#include <vector>
std::vector<int> array; //size = 0
array.resize(someSize); //size = someSize
Declare a pointer:
int * array;