Deleting an array created by new [] with delete [] [duplicate] - c++

This question already has answers here:
How serious is the new/delete operator mismatch error?
(4 answers)
Closed 6 years ago.
Consider the following piece of code:
#include <iostream>
#include <limits>
using namespace std;
struct my{
int a;
~my(){
cout << "d\n";
}
};
int main(){
my* a = new my[100];
// cout << (void*)a << " " << (void*)&(a[0]) << endl;
delete a; // I know I should use delete [],
// but just to find out what would happen if I do this.
}
The program is printing d and then gives a segmentation fault. The implementation of delete assumes that an area of size sizeof(type) has been allocated and that much memory has to be freed. Whereas delete [] first reads the number of elements which has been allocated. I found that most implementations store this number n in the beginning of the allocated memory. delete [] fetches n from the beginning and the goes on to free n * sizeof(type) bytes of allocated memory. I don't understand why the above program gives segfault. I tried printing the addresses a and &(a[0]) and they are exactly the same, so any possibility that delete was trying to clear the area where n was stored is simply not true. Can someone please tell what is going on?
Note: This does not happen when we allocate arrays of basic types like int, double etc.

The behaviour on using delete on a pointer acquired by new[] is undefined. (Some C++ runtime libraries are implemented in such a way that an array of plain old data types is deleted correctly when you write delete).
Really there is nothing else to say.

what was allocated with new must be freed by delete, what was by new[] must be freed by delete[].
don't mix new for allocating and another APIs to free like Windows GlobalFree().
to delete correctly a:
delete[] a;
if you call delete in a dynamic array will cause an undefined behaviour

Related

C++ programming, dynamical memory is not working properly using malloc and calloc

I have just started learning C++ and I came on a problem I couldn't find on the Internet so I hope you can help me with.
This is my code:
int* a;
int* b;
a = (int*)calloc(1, sizeof(int));
b = (int*)calloc(5, sizeof(int));
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
What compiler returns me is: 8, 8.
If I use:
cout << sizeof(*a) << endl;
cout << sizeof(*b) << endl;
Compiler returns 4, 4.
The same thing is with malloc. I am using .
What am I doing wrong? Why isn't the size of b 20 as it is 5 times bigger if int is 4 bytes long?
Thanks!
sizeof(*a) and sizeof(*b) are always going to be equal to 4. It seems you expect them to return the size of arrays, but you need to understand that a and b are not arrays. They are pointers to int. If sizeof(int) is 4, then sizeof(*a) is also going to be 4, and this is already known at compile time.
With that being said, you do not need to use the C library functions malloc() and calloc() in C++. If you need manual memory allocation, use new and delete:
a = new int;
b = new int[5];
If you need to do zero-initialization like calloc does, just use () to default-construct the allocated integers:
a = new int();
b = new int[5]();
Instead of free(), use delete or delete[], depending on how new was called previously:
delete a; // Note: no '[]'
delete[] b; // Needs '[]'
However, you do not need manual memory allocation here. Just use std::vector<int>:
#include <vector>
// ...
std::vector<int> a(5); // 5 int elements, zero-initialized.
std::cout << a.size() << '\n'; // Will print '5'.
As a rule of thumb, your C++ code should not have any calls to new, delete, malloc(), calloc() or free(). Doing manual memory management requires more code and is error-prone. Use containers like vector and smart pointers like shared_ptr and unique_ptr instead to reduce the chance of memory and other resource leaks. These safer types are also more convenient. With vector for example, you do not have to remember the size of your allocated memory yourself. The vector keeps track of its size for you. You can also copy vectors easily by just assigning them directly. You also don't need to delete or free() vectors manually. They are automatically deleted when they go out of scope.
As a side-note, I recommend getting rid of the habit of using endl for printing newlines. endl flushes the stream, it doesn't just print a newline. If you use it, you will be constantly flushing the output stream, which is a slow operation. You only rarely need to flush a stream, in which case you can just do so manually with << flush if the need ever arises.
You are taking the sizeof a pointer in the first case and the size of the element int the second. *a is for your intents and purposes the same as a[0]. The size of the pointer is architecture dependent, and the size of the int is 4.
The sizeof value is evaluated at compile time. Dynamic memory allocation occurs at runtime. To find out the amount allocated at run time you can look at overloading the new operator (not recommended) or using the containers as the comments have suggested.
sizeof(a) is the size of the pointer (this is 8 in a 64bit architecture normally), while sizeof(*a) is the size of the pointed to element (an integer value). Nothing returned by sizeof operator has dynamic nature (as the number of elements returned by calloc(3))
By the way, calloc() is strongly deprecated in C++. Its use is reserved to cases in which you have to pass the pointers to C code and for legacy code. Use the operators new and new [] (the last one in this case). But none of these will change things, the sizeof operator will continue returning the values you got. If you want to check the size of the returned array, then check the parameters passed to both operators.

Do I have to delete memory in this case?

Here is a simple program using dynamic memory.
My question is do I have to delete the memory at the and or the struct will take care of it for me?
#include <iostream>
struct Student {
int grade;
char *name;
};
void print(Student name);
int main() {
Student one;
one.grade = 34;
one.name = new char[12];
int i;
for (i = 0; i < 11; ++i) {
one.name[i] = 'a' + i;
}
one.name[i] = '\0';
print(one);
delete[] one.name;
return 0;
}
void print(Student name) {
std::cout << name.name << " has a score of " << name.grade << "\n";
}
There is a simple rule of thumb- for each call of new you should have one call of delete. In this case you should delete one.name like so : delete [] one.name.
Of course you should do that after you no longer need its value. In this case this is immediately before the return.
Memory allocated dynamically using new or malloc must be freed up when you're done with it using delete or free otherwise you'll get Memory leak.
Make difference between delete and delete[]: the first without subscript operator is used to deleted dynamic memory allocated with new for a pointer. The latter is used for deleting an array allocated dynamically.
So in your case:
one.name = new char[12]; // an array of 12 elements in the heap
delete[] one.name; // freeing up memory
char* c = new char('C'); // a single char in the heap
delete c;
Don't mix new, delete with malloc, free:
This is undefined behavior, as there's no way to reliably prove that memory behind the pointer was allocated correctly (i.e. by new for delete or new[] for delete[]). It's your job to ensure things like that don't happen. It's simple when you use right tools, namely smart pointers. Whenever you say delete, you're doing it wrong.
If you don't want to use unique/shared pointers, you could use a constructor for allocating and a destructor for automatically freeing memory.
If the raw pointer in your structure is an observing pointer, you don't have to delete the memory (of course, someone somewhere in the code must release the memory).
But, if the raw pointer is an owning pointer, you must release it.
In general, every call to new[] must have a matching call to delete[], else you leak memory.
In your code, you invoked new[], so you must invoke delete[] to properly release the memory.
In C++, you can avoid bug-prone leak-prone raw pointers, and use smart pointers or container classes (e.g. std::vector, std::string, etc.) instead.
Creating a Structure does not mean it will handle garbage collection in C++
there is no garbage collection so for every memory you allocate by using new you should use delete keyword to free up space. If you write your code in JAVA you wont have to delete as garbage collector will automatically delete unused references.
Actually the structure won't freeup or delete the memory that you have been created. if in case you want to freeup the space you can do as follows.
#include <iostream>
using namespace std;
int main()
{
char *c = new char[12];
delete[] c;
return(0);
}

Does strcpy'ing a string into into a larger char array cause a memory leak?

Hey all, just wondering whether the following would cause a memory leak?
char* a = "abcd"
char* b = new char[80];
strcpy(b, a);
delete[] b;
Will it delete the whole block of 80 or just the 4 characters copied into it by strcpy? Thanks!
You allocated 80 bytes into b, so delete[] will free 80 bytes. What you did with the array in the meantime is irrelevant.
(Unless, of course, you corrupted the heap, in which case delete[] will probably crash.)
EDIT: As others have pointed out, since b is an array, you need to use delete[] b; instead of delete b;. Some implementations might let you get away with that, but others won't, and it would still be wrong.
A memory leak is when you don't free memory. Just because you allocated more than you need doesn't mean it a memory leak. What you do with your memory is up to you.
Though that should 1) be delete [] b;, or you get undefined behavior, and 2) Be a std::string or std::vector, so you don't both manage and use a resource.
The allocation system will take care of remembering how long the allocations are. The contents don't matter at all.
However, you do need to call the right delete operator. In this case since you allocated new[] you need to delete[].
The last line should be:
delete[] b;
If you allocate one item use delete, if you're allocating an array use delete[].
Since this is tagged C++, here's the C++ version - good to understand memory management via new/delete, but better to avoid doing it by hand using RAII.
#include <string>
#include <iostream>
using namespace std;
int main()
{
string a("abcd");
string aCopy(a);
cout << aCopy << endl;
const char* b(aCopy.c_str());
cout << b << endl;
}

In C++, what happens when the delete operator is called?

In C++, I understand that the delete operator, when used with an array, 'destroys' it, freeing the memory it used. But what happens when this is done?
I figured my program would just mark off the relevant part of the heap being freed for re-usage, and continue on.
But I noticed that also, the first element of the array is set to null, while the other elements are left unchanged. What purpose does this serve?
int * nums = new int[3];
nums[0] = 1;
nums[1] = 2;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
delete [] nums;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
Two things happen when delete[] is called:
If the array is of a type that has a nontrivial destructor, the destructor is called for each of the elements in the array, in reverse order
The memory occupied by the array is released
Accessing the memory that the array occupied after calling delete results in undefined behavior (that is, anything could happen--the data might still be there, or your program might crash when you try to read it, or something else far worse might happen).
The reasons for it being NULL are up to the heap implementation.
Some possible reasons are that it is using the space for it's free-space tracking. It might be using it as a pointer to the next free block. It might be using it to record the size of the free block. It might be writing in some serial number for new/delete debug tracking.
It could just be writing NULL because it feels like it.
Whenever someone says int* nums = new int[3], the runtime system is required to store the number of objects, 3, in a place that can be retrieved knowing only the pointer, nums. The compiler can use any technique it wants to use, but there are two popular ones.
The code generated by nums = new int[3] might store the number 3 in a static associative array, where the pointer nums is used as the lookup key and the number 3 is the associated value. The code generated by delete[] nums would look up the pointer in the associative array, would extract the associated size_t, then would remove the entry from the associative array.
The code generated by nums = new int[3] might allocate an extra sizeof(size_t) bytes of memory (possibly plus some alignment bytes) and put the value 3 just before the first int object. Then delete[] nums would find 3 by looking at the fixed offset before the first int object (that is, before *num) and would deallocate the memory starting at the beginning of the allocation (that is, the block of memory beginning the fixed offset before *nums).
Neither technique is perfect. Here are a few of the tradeoffs.
The associative array technique is slower but safer: if someone forgets the [] when deallocating an array of things, (a) the entry in the associative array would be a leak, and (b) only the first object in the array would be destructed. This may or may not be a serious problem, but at least it might not crash the application.
The overallocation technique is faster but more dangerous: if someone says delete nums where they should have said delete[] nums, the address that is passed to operator delete(void* nums) would not be a valid heap allocation—it would be at least sizeof(size_t) bytes after a valid heap allocation. This would probably corrupt the heap. - C++ FAQs

Is delete p where p is a pointer to array always a memory leak?

following a discussion in a software meeting I've set out to find out if deleting a dynamically allocated, primitives array with plain delete will cause a memory leak.
I have written this tiny program and compiled it with visual studio 2008 running on windows XP:
#include "stdafx.h"
#include "Windows.h"
const unsigned long BLOCK_SIZE = 1024*100000;
int _tmain()
{
for (unsigned int i =0; i < 1024*1000; i++)
{
int* p = new int[1024*100000];
for (int j =0;j<BLOCK_SIZE;j++) p[j]= j % 2;
Sleep(1000);
delete p;
}
}
I than monitored the memory consumption of my application using task manager, surprisingly the memory was allocated and freed correctly, allocated memory did not steadily increase as was expected
I've modified my test program to allocate a non primitive type array :
#include "stdafx.h"
#include "Windows.h"
struct aStruct
{
aStruct() : i(1), j(0) {}
int i;
char j;
} NonePrimitive;
const unsigned long BLOCK_SIZE = 1024*100000;
int _tmain()
{
for (unsigned int i =0; i < 1024*100000; i++)
{
aStruct* p = new aStruct[1024*100000];
Sleep(1000);
delete p;
}
}
after running for for 10 minutes there was no meaningful increase in memory
I compiled the project with warning level 4 and got no warnings.
is it possible that the visual studio run time keep track of the allocated objects types so there is no different between delete and delete[] in that environment ?
delete p, where p is an array is called undefined behaviour.
Specifically, when you allocate an array of raw data types (ints), the compiler doesnt have a lot of work to do, so it turns it into a simple malloc(), so delete p will probably work.
delete p is going to fail, typically, when:
p was a complex data type - delete p; won't know to call individual destructors.
a "user" overloads operator new[] and delete[] to use a different heap to the regular heap.
the debug runtime overloads operator new[] and delete[] to add extra tracking information for the array.
the compiler decides it needs to store extra RTTI information along with the object, which delete p; won't understand, but delete []p; will.
No, it's undefined behavior. Don't do it - use delete[].
In VC++ 7 to 9 it happens to work when the type in question has trivial destructor, but it might stop working on newer versions - usual stuff with undefined behavior. Don't do it anyway.
It's called undefined behaviour; it might work, but you don't know why, so you shouldn't stick with it.
I don't think Visual Studio keeps track of how you allocated the objects, as arrays or plain objects, and magically adds [] to your delete. It probably compiles delete p; to the same code as if you allocated with p = new int, and, as I said, for some reason it works. But you don't know why.
One answer is that yes, it can cause memory leaks, because it doesn't call the destructor for every item in the array. That means that any additional memory owned by items in the array will leak.
The more standards-compliant answer is that it's undefined behaviour. The compiler, for example, has every right to use different memory pools for arrays than for non-array items. Doing the new one way but the delete the other could cause heap corruption.
Your compiler may make guarantees that the standard doesn't, but the first issue remains. For POD items that don't own additional memory (or resources like file handles) you might be OK.
Even if it's safe for your compiler and data items, don't do it anyway - it's also misleading to anyone trying to read your code.
no, you should use delete[] when dealing with arrays
Just using delete won't call the destructors of the objects in the array. While it will possibly work as intended it is undefined as there are some differences in exactly how they work. So you shouldn't use it, even for built in types.
The reason seems not to leak memory is because delete is typically based on free, which already knows how much memory it needs to free. However, the c++ part is unlikely to be cleaned up correctly. I bet that only the destructor of the first object is called.
Using delete with [] tells the compiler to call the destructor on every item of the array.
Not using delete [] can cause memory leaks if used on an array of objects that use dynamic memory allocations like follows:
class AClass
{
public:
AClass()
{
aString = new char[100];
}
~AClass()
{
delete [] aString;
}
private:
const char *aString;
};
int main()
{
AClass * p = new AClass[1000];
delete p; // wrong
return 0;
}