Why do both pointers have the same memory address? - c++

#include <iostream>
using namespace std;
int main()
{
char* MainBlock = new char[100];
char* SubBlock1 = new (MainBlock) char[20];
char* SubBlock2 = new (MainBlock) char [20];
cout << static_cast<void*>(SubBlock1) << " " << static_cast<void*>(SubBlock2);
}
Why do both the pointers in the code above have the same address? I expected SubBlock2 to be 20 bytes after SubBlock 1.
Does this mean I can allocate an endless number of pointers with placement new even though I only have 100 bytes?
How can I ensure that SubBlock6 will be a nullptr or out of bounds using placement new?

Why do both the pointers in the code above have the same address?
Placement new accepts the exact address where it will initialize the object being created. You pass the same address, you get the same address.
Does this mean I can allocate an endless number of pointers with placement new even though I only have 100 bytes?
No. Each placement new reuses the storage. You can of course reuse the storage infinitely many times, but you will only ever have the same 100 characters allocated at most.
How can I ensure that SubBlock6 will be a nullptr or out of bounds using placement new?
There is no way. The onset is on you to provide valid storage for placement new to create the objects. If you don't, the behavior is undefined.
And finally, you don't need to muck about with placement new.
char *SubBlock1 = MainBlock;
char *SubBlock2 = MainBlock + 20;
Partitions the buffer just fine. Just be sure to delete[] only the pointer value stored in MainBlock.

The (MainBlock) argument is a placement argument. You are in fact explicitly telling the program to allocate both SubBlock1 and SubBlock2 at the address of MainBlock.

Each new expression to get the address at which to construct the object calls the appropriate allocation function. Once the allocation is done and the address is returned from the allocation function, it attempts to construct the object exactly at the specified address.
Given char* SubBlock1 = new (MainBlock) char[20];, it calls the following allocation function:
void* operator new[]( std::size_t count, void* ptr );
Called by the standard array form placement new expression. The standard library implementation performs no action and returns ptr unmodified.
As the documentation above say, calling this allocation function does nothing and returns the address you passed unmodified. So, this new expression constructs 20 char exactly at MainBlock. This is why you get the same address for both SubBlock1 and SubBlock2.
Does this mean I can allocate an endless number of pointers with placement new even though I only have 100 bytes?
No. Note that allocation and construction are two different things. In your example, you allocate the memory only once and construct objects many times on it. So the layout of objects constructed on the allocated memory is up to you.

Related

Custom allocator including placement new case

I'm trying to implement a custom allocator for C++ that works on any form of new/delete/malloc/free. How my program works, I allocate at the start of the program a memory pool of x bytes and work with them. For example, when someone writes int* a= new int; my program will return the address from the memory pool which is available and marks it as allocated and that address along with the size allocated is removed from the memory pool. When someone writes delete a; the address is returned to the memory pool and can be used again. My problem is that I don't fully understand how new(placement) works and how should I deal with it, because when my function gets called to allocate memory on new/malloc I have as a parameter only the size of the memory the program needs and I just return an available address to that memory to be used. Consider the following example
auto p = (std::string*)malloc(5 * sizeof(std::string));
void * placement = p;
new(placement) std::string(4, (char)('a'));
std::cout<< *p;
On the first line my custom allocated will return to p an address from my memory pool where there is memory available of a total of 5* sizeof(std::string)), on the third line my custom allocator will allocate again memory returning another address. When I print *p it prints exactly what I was expected aaaa.
Is this how it should work?
A normal new does two things:
allocate storage; and
construct an object.
Now we want to separate these two steps. Allocating raw storage is easy, but there is no "native" way to construct an object at a given address in C++. Therefore, the new operator is overloaded to serve this purpose, by returning the given pointer for the first step.
We don't need a corresponding delete, because we can call the destructor manually. In C++17, std::destroy_at was added to the standard library. Since C++20, std::construct_at can be used to construct an object instead of placement new:
std::construct_at(p, 4, 'a');
The C++ Super-FAQ explains placement new very well:
What is “placement new” and why would I use it?
There are many uses of placement new. The simplest use is to place an
object at a particular location in memory. This is done by supplying
the place as a pointer parameter to the new part of a new expression:
#include <new> // Must #include this to use "placement new"
#include "Fred.h" // Declaration of class Fred
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below)
// The pointers f and place will be equal
// ...
}
Line #1 creates an array of sizeof(Fred) bytes of memory, which is
big enough to hold a Fred object. Line #2 creates a pointer place
that points to the first byte of this memory (experienced C
programmers will note that this step was unnecessary; it’s there only
to make the code more obvious). Line #3 essentially just calls the
constructor Fred::Fred(). The this pointer in the Fred
constructor will be equal to place. The returned pointer f will
therefore be equal to place.
ADVICE: Don’t use this “placement new” syntax unless you have to. Use it only when you really care that an object is placed at a
particular location in memory. For example, when your hardware has a
memory-mapped I/O timer device, and you want to place a Clock object
at that memory location.
DANGER: You are taking sole responsibility that the pointer you pass to the “placement new” operator points to a region of memory that is
big enough and is properly aligned for the object type that you’re
creating. Neither the compiler nor the run-time system make any
attempt to check whether you did this right. If your Fred class
needs to be aligned on a 4 byte boundary but you supplied a location
that isn’t properly aligned, you can have a serious disaster on your
hands (if you don’t know what “alignment” means, please don’t use
the placement new syntax). You have been warned.
You are also solely responsible for destructing the placed object.
This is done by explicitly calling the destructor:
void someCode()
{
char memory[sizeof(Fred)];
void* p = memory;
Fred* f = new(p) Fred();
// ...
f->~Fred(); // Explicitly call the destructor for the placed object
}
This is about the only time you ever explicitly call a destructor.

Use of new and delete in C++

I need help in understanding when shall I use the following options
char *a = new char();
and
char *a = new char[sizeof(int)+1];
and how the respective memory freeing calls should be made?
Any time you use new T, you have to call delete on the resulting pointer afterwards.
Any time you use new T[n], you have to call delete[] on the resulting pointer afterwards.
And that's really all there is to it.
But note that you typically shouldn't use them at all.
If you need a string, don't allocate a char array. Just declare a std::string (without using new). If you need an array whose size is determined at runtime, don't allocate an array. Declare a std::vector (without using new).
The fist one allocates a single char. You delete it with:
delete a;
The second one allocates an array of chars. The length you have chosen is a little strange. You deallocate it with:
delete[] a;
Now... I hope you don't think you can put a stringified number in the second a (something like "123456", because you'll need many more bytes. Let's say at least 12 if an int is 32 bits. There is a funny formula to calculate the minimum length necessary. It's an approximation of the log10 https://stackoverflow.com/a/2338397/613130
To be clear, on my machine sizeof(int) == 4, but in an int I can put -2147483648 that is 10 digits plus the -, so 11 (plus the zero terminator)
None of the expressions you show make much sense.
Also, as a general rule, never use an explicit delete (leave that to smart pointers and collections), and try to avoid using any explicit new.
For simple strings with char elements, just use
std::string a;
This is an example of leaving the new-ing and delete-ing to a library class (which is strongly preferable), in this case std::string.
Include the <string> header to get a declaration of the std::string type.
char *a = new char();
This creates a pointer to a single initialized char.
char *a = new char;
Creates a pointer to a single uninitialized char.
char *a = new char[sizeof(int)+1];
Creates a dynamically allocated char array, of size sizeof(int)+1, i.e. an uninitialized c-string of size sizeof(int)+1. Probably 5 or 9, depending on sizeof(int).
char *a = new char[sizeof(int)+1]();
The same, but the string is initialized.
You need to explicitly free the memory with delete for a single char* and delete[] for the char array.
Another thing worth pointing out as well as the other answers is do not mix the two statements up - you should know whether you allocated a pointer or an array to char* c so that:
You call the correct delete/delete[] operator when cleaning up memory
You do not try accessing data beyond the pointer's scope.
For example, if you did:
// Create a pointer to a single char and set the value
char* c = new char();
*c = 'a';
// Access the pointer using array syntax
char tmp1 = c[0]; // Works, returns 'a'
char tmp2 = c[1]; // Illegal!
Because there are no safe-guards on pointers trying to access c[1] would do something, but in this context it will not return what you expect, it will most likely return memory stored after the char* c pointer or random memory.

c++ what is "pointer = new type" as opposed to "pointer = new type []"?

In many tutorials, the first code samples about dynamic memory start along the lines of:
int * pointer;
pointer = new int; // version 1
//OR
pointer = new int [20]; // version 2
They always proceed to explain how the second version works, but totally avoid talking about the first version.
What I want to know is, what does pointer = new int create? What can I do with it? What does it mean? Every tutorial without fail will avoid talking about the first version entirely. All I've found out (through messing about) is this:
#include <iostream>
using namespace std;
int main()
{
int * pointer;
pointer = new int;
pointer[2] = 1932; // pointer [2] exists? and i can assign to it?!
cout << pointer[2] << endl; // ... and access it successfully?!
};
The fact that I can subscript pointer tells me so far that pointer = new int implicitly creates an array. But if so, then what size is it?
If someone could help clear this all up for me, I'd be grateful...
My teacher explained it like this.
Think of cinema. The actual seats are memory allocations and the ticket you get are the pointers.
int * pointer = new int;
This would be a cinema with one seat, and pointer would be the ticket to that seat
pointer = new int [20]
This would be a cinema with 20 seats and pointer would be the ticket to the first seat. pointer[1] would be the ticket to the second seat and pointer[19] would be the ticket to the last seat.
When you do int* pointer = new int; and then access pointer[2] you're letting someone sit in the aisle, meaning undefined behaviour
This is a typical error in C and C++ for beginners. The first sentence, creates a space for holding just an int. The second one creates a space for holding 20 of those ints. In both cases, however, it assigns the address of the beginning of the dynamically-reserved area to the pointer variable.
To add to the confusion, you can access pointers with indices (as you put pointer[2]) even when the memory they're pointing is not valid. In the case of:
int* pointer = new int;
you can access pointer[2], but you'd have an undefined behavior. Note that you have to check that these accesses don't actually occur, and the compiler can do usually little in preventing this type of errors.
This creates only one integer.
pointer = new int; // version 1
This creates 20 integers.
pointer = new int [20] // version 2
The below is invalid, since pointer[2] translates as *(pointer + 2) ; which is not been created/allocated.
int main()
{
int * pointer;
pointer = new int;
pointer[2] = 1932; // pointer [2] exists? and i can assign to it?!
cout << pointer[2] << endl; // ... and access it succesfuly?!
};
Cheers!
new int[20] allocates memory for an integer array of size 20, and returns a pointer to it.
new int simply allocates memory for one integer, and returns a pointer to it. Implicitly, that is the same as new int[1].
You can dereference (i.e. use *p) on both pointers, but you should only use p[i] on the pointer returned by the new int[20].
p[0] will still work on both, but you might mess up and put a wrong index by accident.
Update: Another difference is that you must use delete[] for the array, and delete for the integer.
pointer = new int allocates enough memory on the heap to store one int.
pointer = new int [20] allocates memory to store 20 ints.
Both calls return a pointer to the newly allocated memory.
Note: Do not rely on the allocated memory being initialized, it may contain random values.
pointer = new int; allocates an integer and stores it's address in pointer. pointer[2] is a synonym for pointer + 2. To understand it, read about pointer arithmetic. This line is actually undefined behavior, because you are accessing memory that you did not previously allocate, and it works because you got lucky.
int* p = new int allocates memory for one integer. It does not implictly create an array. The way you are accessing the pointer using p[2] will cause the undefined behavior as you are writing to an invalid memory location. You can create an array only if you use new[] syntax. In such a case you need to release the memory using delete[]. If you have allocated memory using new then it means you are creating a single object and you need to release the memory using delete.
*"The fact that i can subscript pointer tells me so far that I pointer = new int implicitly creates an array. but if so, then what size is it?"
*
This was the part of the question which I liked the most and which you emphasize upon.
As we all know dynamic memory allocation makes use of the space on the Stack which is specific to the given program.
When we take a closer look onto the definition of new operator :-
void* operator new[] (std::size_t size) throw (std::bad_alloc);
This actually represents an array of objects of that particular size and if this is successful, then it automatically Constructs each of the Objects in the array. Thus we are free to use the objects within the bound of the size because it has already been initialized/constructed.
int * pointer = new int;
On the other hand for the above example there's every possibility of an undefined behaviour when any of
*(pointer + k) or *(k + pointer)
are used. Though the particular memory location can be accessed with the use of pointers, there's no guarantee because the particular Object for the same was not created nor constructed.This can be thought of as a space which was not allocated on the Stack for the particular program.
Hope this helps.
It does not create array. It creates a single integer and returns the pointer to that integer. When you write pointer[2] you refer to a memory which you have not allocated. You need to be carefull and not to do this. That memory can be edited from the external program which you, I belive, don't want.
int * pointer; pointer = new int; // version 1
//OR
pointer = new int [20] // version 2
what I want to know is, what does pointer = new int create? what can I do with it? what does it mean? Every tutorial without fail will avoid talking about the first version entirely
The reason the tutorial doesn't rell you what to do with it is that it really is totally useless! It allocates a single int and gives you a pointer to that.
The problem is that if you want an int, why don't you just declare one?
int i;

Which to use - "operator new" or "operator new[]" - to allocate a block of raw memory in C++?

My C++ program needs a block of uninitialized memory and a void* pointer to that block so that I can give it to a third party library. I want to pass control of the block lifetime to the library, so I don't want to use std::vector. When the library is done with the block it will call a callback that I have to supply and that will deallocate the block. In C I would use malloc() and later free().
In C++ I can either call ::operator new or ::operator new[] and ::operator delete or operator delete[] respectively later:
void* newBlock = ::operator new( sizeOfBlock );
// then, later
::operator delete( newBlock );
Looks like both ::operator new and ::operator new[] have exactly the same signature and exactly the same behavior. The same for ::operator delete and ::operator delete[]. The only thing I shouldn't do is pairing operator new with operator delete[] and vice versa - undefined behavior. Other than that which pair do I choose and why?
Use new with a single object and new[] with an array of objects. So, for example:
int* x = new int; // Allocates single int
int* y = new int[5]; // Allocates an array of integers
*x = 10; // Assignment to single value
y[0] = 8; // Assignment to element of the array
If all you are doing is allocating a memory buffer, then allocate an array of char as in:
int bufferlen = /* choose a buffer size somehow */
char* buffer = new char[bufferlen];
// now can refer to buffer[0] ... buffer[bufferlen-1]
However, in C++, you should really use std::vector for arbitrary arrays, and you should use std::string for character arrays that are to be interpreted or used as strings.
There is no reason to invoke ::operator new or ::operator new[] explicitly rather than using the ordinary syntax for these calls. For POD and primitive types (e.g. char) no initialization will take place. If you need to get a void* buffer, then simply use static_cast to convert char* to void*.
The advantage of the C++ new operators over C's malloc() and free() is that the former throws an exception if there is not enough memory, rather than returning NULL.
Regarding choosing new(size) and new[] for character buffers, I'd advocate the latter since it is less likely to surprise people maintaining the code later i.e. char* buf = new char[size] and delete[] buf.
The values in the buffer will not be initialised, and there is no range-checking - you have to build a nice C++ object to do that for you, or use an existing object such as std::vector or std::string.
The question cannot be answered sensibly.
Firstly, it is said that the program 'needs' a block of uninitialized memory but, from the code sample given, it seems that the program 'needs' a block of uninitialized and UNTYPED memory which seems not very C++ or OO.
Secondly, a std::vector gives sole and automatic control over a block of typed memory that may or may not change in size according to its use. You can lose this control if an instance of std::vector is created on the heap and tracked with raw pointers just as for any other C or C++ object such as a void* memory block.
Thirdly, what is the intended use of this memory block? The answer to this may or may not dictate the use of operator new or operator new[]. In the design of this program, is there a single interpretation of this memory block? What ownership semantics do you require, if any? Etc, etc.
for allocating memory to array/list use new[] other than that use new...

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