Freeing in the destructor is causing a memory leak - c++

I have to write a stack class template using arrays in C++ for my assignment.
Here is my code:
#include <iostream>
template <typename Type>
class Stack {
private:
int top;
Type items[];
public:
Stack() { top = -1; };
~Stack() { delete[] items; };
void push(Type);
bool isEmpty() const;
Type pop();
Type peek() const;
};
int main (int argc, char *argv[]) {
Stack<double> st;
return 0;
}
template<typename Type>
void Stack<Type>::push(Type item) {
top++;
if(top == sizeof(items) / sizeof(Type)) {
Type buff[] = new Type[top];
std::copy(items,items+top,buff);
delete[] items;
items = new Type[2*top];
std::copy(buff,buff+top,items);
delete[] buff;
}
items[top] = item;
}
template<typename Type>
bool Stack<Type>::isEmpty() const {
return top == -1 ? true : false;
}
template<typename Type>
Type Stack<Type>::pop() {
//TODO
return items[top--];
}
template<typename Type>
Type Stack<Type>::peek() const{
//TODO
return items[top-1];
}
It compiled fine using "g++ -Wall", however when I run the program, I got this error:
* glibc detected * ./lab3: munmap_chunk(): invalid pointer: 0x00007fff41a3cdf8
After trying out a bit with GDB, I found out the error arose from the line:
'free[] items' in the destructor.
I don't understand why freeing an array results in a memory leak? Any clues?

You should only delete[] what you have explicitly allocated with new[]. Your items member is not a dynamically allocated array, so you must not free it as if it were.
On the other hand, you have
Type items[];
which doesn't actually allocate any space in your object instances for the stack.

I don't think that's a memory leak! It's a crash occurring because you deleted a non-heap object.

You haven't new'd items, so you can't delete it in the destructor. Assuming you require 'Stack' to be a dynamically sized class then the items array must be dynamically allocated in which case the declaration for items should be
Type *items; (as hacker mentions above)
and the constructor should call 'items = new Type[ARRAY_SIZE]' to allocate the memory, or at the very least initially assign the 'items' pointer to NULL.
Edit based on comments -
To complete and secure the memory allocation responsibilities for this class you should also include a copy constructor and an assignment operator which allocates new memory and copies the values stored in items to the new object. This avoids the pointer simply being copied by the compiler generated copy constructor or assignment operator which would lead to multiple objects pointing to the same dynamically allocated memory. Upon destruction of the first of these objects this memory will be deleted. Further use of the now deleted memory by the other objects which share the pointer would be likely to result in a crash.
Rather than adding code here I refer you to the code in Martin's answer for this question.

items is a pointer to Type. This pointer must be initialised
before it is used (it is a wild pointer as it is). That
is why your program crashes. That it happens in the
destructor is a coincidence. It could just as well have
happened earlier. E.g. in push() memory is overwritten in the
location that items happens to point to.
You need to allocate memory for a number of elements. See below.
You already have the logic for the dynamic growth of the
array in place. But an array in C++ does not know its size
(it is just a pointer of some type). You need to keep track
of the current capacity/size. Thus instead of
sizeof(items)
define a new member to hold the current capacity.
E.g.:
int capacity;
and in the constructor:
capacity = 100;
items = new Type[capacity];
The last line allocates a number of elements and is the main solution to your problem.
And in push():
if (top == capacity / sizeof(Type)) {
The logic for reallocation will need to change. E.g.:
capacity *= 2;
items = new Type[capacity];
instead of
items = new Type[2*top];
I have just sketched out a solution here. Yon can fill in the details.
Note: you have only one instance of Stack in your program; body of main() is:
Stack<double> st;
If you instead were to assign one instance of Stack to another instance, e.g.
{
Stack<double> st;
Stack<double> st2 = st; //Copy constructor will be invoked for st2. If not defined the compiler generated copy constructor will do a copy of the pointer value.
Stack<double> st3;
st3 = st; //Assignment operator will be invoked for st3. If not defined the compiler generated assignment operator will do a copy of the pointer value.
}
then the copy constructor (to work for st2) and the
assignment operator (to work for st3) for Stack must be
defined properly (make a copy of the referenced member
items). Otherwise a double or triple delete in the destructor and
undefined behavior (e.g. a crash) will be the result when
st, st2 and st3 goes out of scope at the close brace.

The first thing I've seen is that you're likely to mean Type *items, not Type items[].
And then you don't want to (can't) use sizeof on the dynamically allocated data.

Related

C++ class destructor not being called automatically causes memory leak?

(Before anyone asks: no, i didn't forget the delete[] statement)
I was fiddling around with dinamically allocated memory and i run into this issue. I think the best way to explain it is to show you these two pieces of code I wrote. They are very similar, but in one of them my class destructor doesn't get called.
// memleak.cpp
#include <vector>
using namespace std;
class Leak {
vector<int*> list;
public:
void init() {
for (int i = 0; i < 10; i++) {
list.push_back(new int[2] {i, i});
}
}
Leak() = default;
~Leak() {
for (auto &i : list) {
delete[] i;
}
}
};
int main() {
Leak leak;
while (true) {
// I tried explicitly calling the destructor as well,
// but this somehow causes the same memory to be deleted twice
// and segfaults
// leak.~Leak();
leak = Leak();
leak.init();
}
}
// noleak.cpp
#include <vector>
using namespace std;
class Leak {
vector<int*> list;
public:
Leak() {
for (int i = 0; i < 10; i++) {
list.push_back(new int[2] {i, i});
}
};
~Leak() {
for (auto &i : list) {
delete[] i;
}
}
};
int main() {
Leak leak;
while (true) {
leak = Leak();
}
}
I compiled them both with g++ filename.cpp --std=c++14 && ./a.out and used top to check memory usage.
As you can see, the only difference is that, in memleak.cpp, the class constructor doesn't do anything and there is an init() function that does its job. However, if you try this out, you will see that this somehow interferes with the destructor being called and causes a memory leak.
Am i missing something obvious? Thanks in advance.
Also, before anyone suggests not using dinamically allocated memory: I knwow that it isn't always a good practice and so on, but the main thing I'm interested in right now is understanding why my code doesn't work as expected.
This is constructing a temporary object and then assigning it. Since you didn't write an assignment operator, you get a default one. The default one just copies the vector list.
In the first code you have:
Create a temporary Leak object. It has no pointers in its vector.
Assign the temporary object to the leak object. This copies the vector (overwriting the old one)
Delete the temporary object, this deletes 0 pointers since its vector is empty.
Allocate a bunch of memory and store the pointers in the vector.
Repeat.
In the second code you have:
Create a temporary Leak object. Allocate some memory and store the pointers in its vector.
Assign the temporary object to the leak object. This copies the vector (overwriting the old one)
Delete the temporary object, this deletes the 10 pointers in the temporary object's vector.
Repeat.
Note that after leak = Leak(); the same pointers that were in the temporary object's vector are also in leak's vector. Even if they were deleted.
To fix this, you should write an operator = for your class. The rule of 3 is a way to remember that if you have a destructor, you usually need to also write a copy constructor and copy assignment operator. (Since C++11 you can optionally also write a move constructor and move assignment operator, making it the rule of 5)
Your assignment operator would delete the pointers in the vector, clear the vector, allocate new memory to hold the int values from the object being assigned, put those pointers in the vector, and copy the int values. So that the old pointers are cleaned up, and the object being assigned to becomes a copy of the object being assigned from, without sharing the same pointers.
Your class doesn't respect the rule of 3/5/0. The default-generated move-assignment copy-assignment operator in leak = Leak(); makes leak reference the contents of the temporary Leak object, which it deletes promptly at the end of its lifetime, leaving leak with dangling pointers which it will later try to delete again.
Note: this could have gone unnoticed if your implementation of std::vector systematically emptied the original vector upon moving, but that is not guaranteed.
Note 2: the striked out parts above I wrote without realizing that, as StoryTeller pointed out to me, your class does not generate a move-assignment operator because it has a user-declared destructor. A copy-assignment operator is generated and used instead.
Use smart pointers and containers to model your classes (std::vector<std::array<int, 2>>, std::vector<std::vector<int>> or std::vector<std::unique_ptr<int[]>>). Do not use new, delete and raw owning pointers. In the exceedingly rare case where you may need them, be sure to encapsulate them tightly and to carefully apply the aforementioned rule of 3/5/0 (including exception handling).

I need to check if thrown exception from operator=?

Given the following code:
template <class T>
class A {
T* arr;
int size;
public:
A(int size) : arr(new T[size]) , size(size) {
}
//..
A& operator=(const A& a){
if(this == &a){
return *this;
}
this->size = a.size;
T* ar=new T[a.size];
for(int i=0 ; i<size ; i++){
ar[i]=a.arr[i]; // I need to do it at "try-catch" ?
}
delete[] this->arr;
this->arr=ar;
return *this;
}
//...
};
When I copy the elements from the given array, do I need to do it with a try-catch clause or not? is it a good idea or not?
I can see that potentially your T copy could throw due to its own alloc failure or other reasons.
On the other hand your A copy could already throw because it had alloc failure.
Currently you would need to handle the destruction because you have not concreted the array that you have allocated, and all the T instances that you have created need to be destroyed if one of them exceptions, perhaps due to allocation failure.
One quick way to fix that would be to hold the array in a unique_ptr. Then it will be destroyed on exiting context.
Another way may be to reconsider your contract on A after the assignment has exceptioned: It must be valid, i.e. survive being used, but perhaps it need not guarantee to still contain its previous contents, nor all the new contents, so you could decide to destroy its existing array before allocating and assigning a new array, then copying the members. You could decide not to reallocate if the size has not changed, but just re-assign - this would leave a mess of new and old members after an exception, but they would all be valid and safe to delete.
Please ensure that size matches the actual attached array size at all times! Your existing code makes this mistake, but in particular that it is set to null and 0 after the delete and before the assignment; and it is only set to new new size after the assignment of the new pointer.

Error every time the destructor is called

I got a weird message everytime the destructor is called. Since one of my private variable is dynamic allocated array (int *member;), I write the destructor like this:
ClassSet::~ClassSet(){delete []member;}
Everytime the destructor for ClassSet is called, I got an error message:
Windows has triggered a breakpoint in Hw1.exe.
This may be due to a corruption of the heap, which indicates a bug in Hw1.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while Hw1.exe has focus.
entire class:
class ClassSet
{
public:
ClassSet(int n = DEFAULT_MAX_ITEMS);
ClassSet(const ClassSet& other);
ClassSet &operator=(const ClassSet& other);
~ClassSet();
private:
int size;
int *member;
};
ClassSet::ClassSet(int n){
size = n;
member = new int[n];
}
ClassSet::ClassSet(const ClassSet& other){
int i = 0;
this->size = other.size;
member = new int [capacity];
while (i<size)
{
this->member[i] = other.member[i];
i++;
}
}
Multiset& Multiset::operator=(const Multiset &other)
{
if (&other == this){return *this;}
this->size = other.size;
int i = 0;
delete [] member;
member = new int[size];
while (i<other.size)
{
this->member[i] = other.member[i];
i++;
}
return *this;
}
Any idea what's wrong with this destructor?
You failed to implement (or you have implemented incorrectly) one of ClassSet::ClassSet(const ClassSet&) or ClassSet::operator=(const ClassSet&).
In other words, you have violated the Rule of Three.
The best solution, however, is likely not to implement them, but rather to change how you allocate space for your dynamic array. Instead of using new[] and delete[], try replacing that member with a std::vector<>.
Heap corruption is often something detected after-the-fact. It may have to do with your destructor, or as I've seen, can likely happen well before the heap access the error occurs at.
Basically "Heap corruption detected" simply means that on a given access of the heap, Windows decided that the current state of the heap was inconsistent/invalid. Something went bad a while earlier.
These bugs can be really hard to track down. One common cause of heap corruption though is double deletion you deleted something twice inadvertently. This can point at deeper issues with how your data is copied around your code and your design.
This can happen, as others have said, when you don't have an appropriate copy constructor/assignment operator that copies dynamic memory. The "copy" deletes your memory, then the initial class deletes again, causing a double delete.
If you've posted you actual code, then I think the problem is here:
ClassSet::ClassSet(const ClassSet& other){
int i = 0;
this->size = other.size;
member = new int [capacity]; // <--- what is capacity?
while (i<size)
{
this->member[i] = other.member[i];
i++;
}
}
You're sizing the copied array based on something named capacity which doesn't have any obvious relationship to other.size. If capacity is smaller than size the loop that copies elements will corrupt the heap.
Assuming that this is an academic exercise, once you solve this problem you should look into the copy/swap idiom that used for classes like these to ensure exception safety.
If this isn't an academic exercise, then you should be looking at std::vector or other containers that are provided in libraries.
This problem is quite common. The default copy constructor is equivalent to
ClassSet(const ClassSet& other) {
size = other.size;
member = other.member;
}
The problem with this is that when an instance ClassSet is copied, both the original instance and the new instance hold a raw pointer to member. Both destructors will free member, causing the double free problem you are seeing.
For example,
{
ClassSet a
ClassSet b(a); // assert(b.member == a.member)
} // At this point, both a and b will free the same pointer.
You can mitigate this by not allowing copying, or moving the pointer instead of copying.

Double free or corruption after queue::push

#include <queue>
using namespace std;
class Test{
int *myArray;
public:
Test(){
myArray = new int[10];
}
~Test(){
delete[] myArray;
}
};
int main(){
queue<Test> q
Test t;
q.push(t);
}
After I run this, I get a runtime error "double free or corruption". If I get rid of the destructor content (the delete) it works fine. What's wrong?
Let's talk about copying objects in C++.
Test t;, calls the default constructor, which allocates a new array of integers. This is fine, and your expected behavior.
Trouble comes when you push t into your queue using q.push(t). If you're familiar with Java, C#, or almost any other object-oriented language, you might expect the object you created earler to be added to the queue, but C++ doesn't work that way.
When we take a look at std::queue::push method, we see that the element that gets added to the queue is "initialized to a copy of x." It's actually a brand new object that uses the copy constructor to duplicate every member of your original Test object to make a new Test.
Your C++ compiler generates a copy constructor for you by default! That's pretty handy, but causes problems with pointer members. In your example, remember that int *myArray is just a memory address; when the value of myArray is copied from the old object to the new one, you'll now have two objects pointing to the same array in memory. This isn't intrinsically bad, but the destructor will then try to delete the same array twice, hence the "double free or corruption" runtime error.
How do I fix it?
The first step is to implement a copy constructor, which can safely copy the data from one object to another. For simplicity, it could look something like this:
Test(const Test& other){
myArray = new int[10];
memcpy( myArray, other.myArray, 10 );
}
Now when you're copying Test objects, a new array will be allocated for the new object, and the values of the array will be copied as well.
We're not completely out trouble yet, though. There's another method that the compiler generates for you that could lead to similar problems - assignment. The difference is that with assignment, we already have an existing object whose memory needs to be managed appropriately. Here's a basic assignment operator implementation:
Test& operator= (const Test& other){
if (this != &other) {
memcpy( myArray, other.myArray, 10 );
}
return *this;
}
The important part here is that we're copying the data from the other array into this object's array, keeping each object's memory separate. We also have a check for self-assignment; otherwise, we'd be copying from ourselves to ourselves, which may throw an error (not sure what it's supposed to do). If we were deleting and allocating more memory, the self-assignment check prevents us from deleting memory from which we need to copy.
The problem is that your class contains a managed RAW pointer but does not implement the rule of three (five in C++11). As a result you are getting (expectedly) a double delete because of copying.
If you are learning you should learn how to implement the rule of three (five). But that is not the correct solution to this problem. You should be using standard container objects rather than try to manage your own internal container. The exact container will depend on what you are trying to do but std::vector is a good default (and you can change afterwords if it is not opimal).
#include <queue>
#include <vector>
class Test{
std::vector<int> myArray;
public:
Test(): myArray(10){
}
};
int main(){
queue<Test> q
Test t;
q.push(t);
}
The reason you should use a standard container is the separation of concerns. Your class should be concerned with either business logic or resource management (not both). Assuming Test is some class you are using to maintain some state about your program then it is business logic and it should not be doing resource management. If on the other hand Test is supposed to manage an array then you probably need to learn more about what is available inside the standard library.
You are getting double free or corruption because first destructor is for object q in this case the memory allocated by new will be free.Next time when detructor will be called for object t at that time the memory is already free (done for q) hence when in destructor delete[] myArray; will execute it will throw double free or corruption.
The reason is that both object sharing the same memory so define \copy, assignment, and equal operator as mentioned in above answer.
You need to define a copy constructor, assignment, operator.
class Test {
Test(const Test &that); //Copy constructor
Test& operator= (const Test &rhs); //assignment operator
}
Your copy that is pushed on the queue is pointing to the same memory your original is. When the first is destructed, it deletes the memory. The second destructs and tries to delete the same memory.
You can also try to check null before delete such that
if(myArray) { delete[] myArray; myArray = NULL; }
or you can define all delete operations ina safe manner like this:
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p) { delete (p); (p) = NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p) = NULL; } }
#endif
and then use
SAFE_DELETE_ARRAY(myArray);
Um, shouldn't the destructor be calling delete, rather than delete[]?

How does delete[] know it's an array?

Alright, I think we all agree that what happens with the following code is undefined, depending on what is passed,
void deleteForMe(int* pointer)
{
delete[] pointer;
}
The pointer could be all sorts of different things, and so performing an unconditional delete[] on it is undefined. However, let's assume that we are indeed passing an array pointer,
int main()
{
int* arr = new int[5];
deleteForMe(arr);
return 0;
}
My question is, in this case where the pointer is an array, who is it that knows this? I mean, from the language/compiler's point of view, it has no idea whether or not arr is an array pointer versus a pointer to a single int. Heck, it doesn't even know whether arr was dynamically created. Yet, if I do the following instead,
int main()
{
int* num = new int(1);
deleteForMe(num);
return 0;
}
The OS is smart enough to only delete one int and not go on some type of 'killing spree' by deleting the rest of the memory beyond that point (contrast that with strlen and a non-\0-terminated string -- it will keep going until it hits 0).
So whose job is it to remember these things? Does the OS keep some type of record in the background? (I mean, I realise that I started this post by saying that what happens is undefined, but the fact is, the 'killing spree' scenario doesn't happen, so therefore in the practical world someone is remembering.)
One question that the answers given so far don't seem to address: if the runtime libraries (not the OS, really) can keep track of the number of things in the array, then why do we need the delete[] syntax at all? Why can't a single delete form be used to handle all deletes?
The answer to this goes back to C++'s roots as a C-compatible language (which it no longer really strives to be.) Stroustrup's philosophy was that the programmer should not have to pay for any features that they aren't using. If they're not using arrays, then they should not have to carry the cost of object arrays for every allocated chunk of memory.
That is, if your code simply does
Foo* foo = new Foo;
then the memory space that's allocated for foo shouldn't include any extra overhead that would be needed to support arrays of Foo.
Since only array allocations are set up to carry the extra array size information, you then need to tell the runtime libraries to look for that information when you delete the objects. That's why we need to use
delete[] bar;
instead of just
delete bar;
if bar is a pointer to an array.
For most of us (myself included), that fussiness about a few extra bytes of memory seems quaint these days. But there are still some situations where saving a few bytes (from what could be a very high number of memory blocks) can be important.
The compiler doesn't know it's an array, it's trusting the programmer. Deleting a pointer to a single int with delete [] would result in undefined behavior. Your second main() example is unsafe, even if it doesn't immediately crash.
The compiler does have to keep track of how many objects need to be deleted somehow. It may do this by over-allocating enough to store the array size. For more details, see the C++ Super FAQ.
Yes, the OS keeps some things in the 'background.' For example, if you run
int* num = new int[5];
the OS can allocate 4 extra bytes, store the size of the allocation in the first 4 bytes of the allocated memory and return an offset pointer (ie, it allocates memory spaces 1000 to 1024 but the pointer returned points to 1004, with locations 1000-1003 storing the size of the allocation). Then, when delete is called, it can look at 4 bytes before the pointer passed to it to find the size of the allocation.
I am sure that there are other ways of tracking the size of an allocation, but that's one option.
This is very similar to this question and it has many of the details your are looking for.
But suffice to say, it is not the job of the OS to track any of this. It's actually the runtime libraries or the underlying memory manager that will track the size of the array. This is usually done by allocating extra memory up front and storing the size of the array in that location (most use a head node).
This is viewable on some implementations by executing the following code
int* pArray = new int[5];
int size = *(pArray-1);
delete or delete[] would probably both free the memory allocated (memory pointed), but the big difference is that delete on an array won't call the destructor of each element of the array.
Anyway, mixing new/new[] and delete/delete[] is probably UB.
It doesn't know it's an array, that's why you have to supply delete[] instead of regular old delete.
I had a similar question to this. In C, you allocate memory with malloc() (or another similar function), and delete it with free(). There is only one malloc(), which simply allocates a certain number of bytes. There is only one free(), which simply takes a pointer as it's parameter.
So why is it that in C you can just hand over the pointer to free, but in C++ you must tell it whether it's an array or a single variable?
The answer, I've learned, has to do with class destructors.
If you allocate an instance of a class MyClass...
classes = new MyClass[3];
And delete it with delete, you may only get the destructor for the first instance of MyClass called. If you use delete[], you can be assured that the destructor will be called for all instances in the array.
THIS is the important difference. If you're simply working with standard types (e.g. int) you won't really see this issue. Plus, you should remember that behavior for using delete on new[] and delete[] on new is undefined--it may not work the same way on every compiler/system.
It's up to the runtime which is responsible for the memory allocation, in the same way that you can delete an array created with malloc in standard C using free. I think each compiler implements it differently. One common way is to allocate an extra cell for the array size.
However, the runtime is not smart enough to detect whether or not it is an array or a pointer, you have to inform it, and if you are mistaken, you either don't delete correctly (E.g., ptr instead of array), or you end up taking an unrelated value for the size and cause significant damage.
ONE OF THE approaches for compilers is to allocate a little more memory and store count of elements in the head element.
Example how it could be done:
Here
int* i = new int[4];
compiler will allocate sizeof(int)*5 bytes.
int *temp = malloc(sizeof(int)*5)
Will store 4 in first sizeof(int) bytes
*temp = 4;
and set i
i = temp + 1;
So i points to array of 4 elements, not 5.
And
delete[] i;
will be processed following way
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements if needed
... that are stored in temp + 1, temp + 2, ... temp + 4
free (temp)
Semantically, both versions of delete operator in C++ can "eat" any pointer; however, if a pointer to a single object is given to delete[], then UB will result, meaning anything may happen, including a system crash or nothing at all.
C++ requires the programmer to choose the proper version of the delete operator depending on the subject of deallocation: array or single object.
If the compiler could automatically determine whether a pointer passed to the delete operator was a pointer array, then there would be only one delete operator in C++, which would suffice for both cases.
Agree that the compiler doesn't know if it is an array or not. It is up to the programmer.
The compiler sometimes keep track of how many objects need to be deleted by over-allocating enough to store the array size, but not always necessary.
For a complete specification when extra storage is allocated, please refer to C++ ABI (how compilers are implemented): Itanium C++ ABI: Array Operator new Cookies
"undefined behaviour" simply means the language spec makes no gaurantees as to what will happen. It doesn't nessacerally mean that something bad will happen.
So whose job is it to remember these things? Does the OS keep some type of record in the background? (I mean, I realise that I started this post by saying that what happens is undefined, but the fact is, the 'killing spree' scenario doesn't happen, so therefore in the practical world someone is remembering.)
There are typically two layers here. The underlying memory manager and the C++ implementation.
Most memory managers were designed to meet the needs of the C language. In C the "free" function does not require the user to specify the size of the block. Therefore the memory manager will remember (among other things) the size of the block of memory that was allocated. This may be larger than the block the C++ implementation asked for. Typically the memory manager will store it's metadata before the allocated block of memory.
C++ has a culture of "you only pay for what you use". Therefore the C++ implementation will generally only remember the size of the array if it needs to do so for it's own purposes, typically because the type has a non-trival destructor.
So for types with a trivial destructor the implementation of "delete" and "delete []" is typically the same. The C++ implementation simply passes the pointer to the underlying memory manager. Something like
free(p)
On the other hand for types with a non-trivial destructor "delete" and "delete []" are likely to be different. "delete" would be somthing like (where T is the type that the pointer points to)
p->~T();
free(p);
While "delete []" would be something like.
size_t * pcount = ((size_t *)p)-1;
size_t count = *count;
for (size_t i=0;i<count;i++) {
p[i].~T();
}
char * pmemblock = ((char *)p) - max(sizeof(size_t),alignof(T));
free(pmemblock);
You cannot use delete for an array, and you cannot use delete [] for a non-array.
Hey ho well it depends of what you allocating with new[] expression when you allocate array of build in types or class / structure and you don't provide your constructor and destructor the operator will treat it as a size "sizeof(object)*numObjects" rather than object array therefore in this case number of allocated objects will not be stored anywhere, however if you allocate object array and you provide constructor and destructor in your object than behavior change, new expression will allocate 4 bytes more and store number of objects in first 4 bytes so the destructor for each one of them can be called and therefore new[] expression will return pointer shifted by 4 bytes forward, than when the memory is returned the delete[] expression will call a function template first, iterate through array of objects and call destructor for each one of them. I've created this simple code witch overloads new[] and delete[] expressions and provides a template function to deallocate memory and call destructor for each object if needed:
// overloaded new expression
void* operator new[]( size_t size )
{
// allocate 4 bytes more see comment below
int* ptr = (int*)malloc( size + 4 );
// set value stored at address to 0
// and shift pointer by 4 bytes to avoid situation that
// might arise where two memory blocks
// are adjacent and non-zero
*ptr = 0;
++ptr;
return ptr;
}
//////////////////////////////////////////
// overloaded delete expression
void static operator delete[]( void* ptr )
{
// decrement value of pointer to get the
// "Real Pointer Value"
int* realPtr = (int*)ptr;
--realPtr;
free( realPtr );
}
//////////////////////////////////////////
// Template used to call destructor if needed
// and call appropriate delete
template<class T>
void Deallocate( T* ptr )
{
int* instanceCount = (int*)ptr;
--instanceCount;
if(*instanceCount > 0) // if larger than 0 array is being deleted
{
// call destructor for each object
for(int i = 0; i < *instanceCount; i++)
{
ptr[i].~T();
}
// call delete passing instance count witch points
// to begin of array memory
::operator delete[]( instanceCount );
}
else
{
// single instance deleted call destructor
// and delete passing ptr
ptr->~T();
::operator delete[]( ptr );
}
}
// Replace calls to new and delete
#define MyNew ::new
#define MyDelete(ptr) Deallocate(ptr)
// structure with constructor/ destructor
struct StructureOne
{
StructureOne():
someInt(0)
{}
~StructureOne()
{
someInt = 0;
}
int someInt;
};
//////////////////////////////
// structure without constructor/ destructor
struct StructureTwo
{
int someInt;
};
//////////////////////////////
void main(void)
{
const unsigned int numElements = 30;
StructureOne* structOne = nullptr;
StructureTwo* structTwo = nullptr;
int* basicType = nullptr;
size_t ArraySize = 0;
/**********************************************************************/
// basic type array
// place break point here and in new expression
// check size and compare it with size passed
// in to new expression size will be the same
ArraySize = sizeof( int ) * numElements;
// this will be treated as size rather than object array as there is no
// constructor and destructor. value assigned to basicType pointer
// will be the same as value of "++ptr" in new expression
basicType = MyNew int[numElements];
// Place break point in template function to see the behavior
// destructors will not be called and it will be treated as
// single instance of size equal to "sizeof( int ) * numElements"
MyDelete( basicType );
/**********************************************************************/
// structure without constructor and destructor array
// behavior will be the same as with basic type
// place break point here and in new expression
// check size and compare it with size passed
// in to new expression size will be the same
ArraySize = sizeof( StructureTwo ) * numElements;
// this will be treated as size rather than object array as there is no
// constructor and destructor value assigned to structTwo pointer
// will be the same as value of "++ptr" in new expression
structTwo = MyNew StructureTwo[numElements];
// Place break point in template function to see the behavior
// destructors will not be called and it will be treated as
// single instance of size equal to "sizeof( StructureTwo ) * numElements"
MyDelete( structTwo );
/**********************************************************************/
// structure with constructor and destructor array
// place break point check size and compare it with size passed in
// new expression size in expression will be larger by 4 bytes
ArraySize = sizeof( StructureOne ) * numElements;
// value assigned to "structOne pointer" will be different
// of "++ptr" in new expression "shifted by another 4 bytes"
structOne = MyNew StructureOne[numElements];
// Place break point in template function to see the behavior
// destructors will be called for each array object
MyDelete( structOne );
}
///////////////////////////////////////////
just define a destructor inside a class and execute your code with both syntax
delete pointer
delete [] pointer
according to the output u can find the solutions
The answer:
int* pArray = new int[5];
int size = *(pArray-1);
Posted above is not correct and produces invalid value.
The "-1"counts elements
On 64 bit Windows OS the correct buffer size resides in Ptr - 4 bytes address