Malloc vs new -- different padding - c++

I'm reviewing someone else's C++ code for our project that uses MPI for high-performance computing (10^5 - 10^6 cores). The code is intended to allow for communications between (potentially) different machines on different architectures. He's written a comment that says something along the lines of:
We'd normally use new and delete, but here I'm using malloc and free. This is necessary because some compilers will pad the data differently when new is used, leading to errors in transferring data between different platforms. This doesn't happen with malloc.
This does not fit with anything I know from standard new vs malloc questions.
What is the difference between new/delete and malloc/free? hints at the idea that the compiler could calculate the size of an object differently (but then why does that differ from using sizeof?).
malloc & placement new vs. new is a fairly popular question but only talks about new using constructors where malloc doesn't, which isn't relevant to this.
how does malloc understand alignment? says that memory is guaranteed to be properly aligned with either new or malloc which is what I'd previously thought.
My guess is that he's misdiagnosed his own bug some time in the past and deduced that new and malloc give different amounts of padding, which I think probably isn't true. But I can't find the answer with Google or in any previous question.
Help me, StackOverflow, you're my only hope!

IIRC there's one picky point. malloc is guaranteed to return an address aligned for any standard type. ::operator new(n) is only guaranteed to return an address aligned for any standard type no larger than n, and if T isn't a character type then new T[n] is only required to return an address aligned for T.
But this is only relevant when you're playing implementation-specific tricks like using the bottom few bits of a pointer to store flags, or otherwise relying on the address to have more alignment than it strictly needs.
It doesn't affect padding within the object, which necessarily has exactly the same layout regardless of how you allocated the memory it occupies. So it's hard to see how the difference could result in errors transferring data.
Is there any sign what the author of that comment thinks about objects on the stack or in globals, whether in his opinion they're "padded like malloc" or "padded like new"? That might give clues to where the idea came from.
Maybe he's confused, but maybe the code he's talking about is more than a straight difference between malloc(sizeof(Foo) * n) vs new Foo[n]. Maybe it's more like:
malloc((sizeof(int) + sizeof(char)) * n);
vs.
struct Foo { int a; char b; }
new Foo[n];
That is, maybe he's saying "I use malloc", but means "I manually pack the data into unaligned locations instead of using a struct". Actually malloc is not needed in order to manually pack the struct, but failing to realize that is a lesser degree of confusion. It is necessary to define the data layout sent over the wire. Different implementations will pad the data differently when the struct is used.

Your colleague may have had new[]/delete[]'s magic cookie in mind (this is the information the implementation uses when deleting an array). However, this would not have been a problem if the allocation beginning at the address returned by new[] were used (as opposed to the allocator's).
Packing seems more probable. Variations in ABIs could (for example) result in a different number of trailing bytes added at the end a structure (this is influenced by alignment, also consider arrays). With malloc, the position of a structure could be specified and thus more easily portable to a foreign ABI. These variations are normally prevented by specifying alignment and packing of transfer structures.

The layout of an object can't depend on whether it was allocated using malloc or new. They both return the same kind of pointer, and when you pass this pointer to other functions they won't know how the object was allocated. sizeof *ptr is just dependent on the declaration of ptr, not how it was assigned.

I think you are right. Padding is done by the compiler not new or malloc. Padding considerations would apply even if you declared an array or struct without using new or malloc at all. In any case while I can see how different implementations of new and malloc could cause problems when porting code between platforms, I completely fail to see how they could cause problems transferring data between platforms.

When I want to control the layout of my plain old data structure, with MS Visual compilers I use #pragma pack(1). I suppose such a precompiler directive is supported for most compilers, like for example gcc.
This has the consequence of aligning all fields of the structures one behind the other, without empty spaces.
If the platform on the other end does the same ( i.e. compiled its data exchange structure with a padding of 1), then the data retrieved on both side justs fits well.
Thus I have never had to to play with malloc in C++.
At worst I would have considered overloading the new operator so as it performs some tricky things, rather than using malloc directly in C++.

This is my wild guess of where this thing is coming from. As you mentioned, problem is with data transmission over MPI.
Personally, for my complicated data structures that I want to send/receive over MPI, I always implement serialization/deserialization methods that pack/unpack the whole thing into/from an array of chars. Now, due to padding we know that that size of the structure could be larger than the size of its members and thus one also needs to calculate the unpadded size of the data structure so that we know how many bytes are being sent/received.
For instance if you want to send/receive std::vector<Foo> A over MPI with the said technique, it is wrong to assume the size of resulting array of chars is A.size()*sizeof(Foo) in general. In other words, each class that implements serialize/deserialize methods, should also implement a method that reports the size of the array (or better yet store the array in a container). This might become the reason behind a bug. One way or another, however, that has nothing to do with new vs malloc as pointed out in this thread.

In c++: newkeyword is used to allocate some particular bytes of memory with respect to some data-structure. For example, you have defined some class or structure and you want to allocate memory for its object.
myclass *my = new myclass();
or
int *i = new int(2);
But in all cases you need the defined datatype (class, struct, union, int, char etc...) and only that bytes of memory will be allocated which is required for its object/variable. (ie; multiples of that datatype).
But in case of malloc() method, you can allocate any bytes of memory and you don't need to specify the data type at all times. Here you can observe it in few possibilities of malloc():
void *v = malloc(23);
or
void *x = malloc(sizeof(int) * 23);
or
char *c = (char*)malloc(sizeof(char)*35);

malloc is a type of function
and new is a type of data type in c++
in c++, if we use malloc than we must and should use typecast otherwise compiler give you error
and if we use new data type for allocation of memory than we no need to typecast

Related

How to modernize memalign in a C++ codebase?

I am modernizing/updating some old code that was originally written in C but is now used in a C++ codebase (no need to be backwards compatible). A bunch of this code is memory optimized with memalign with which I am very inexperienced with so my question is how one would update this code (or just leave it like it is) and whether there's even still any point to having it there at all:
The declaration:
float *table_pf;
And how it's initialized in the constructor:
table_pf = (float*)memalign(32, sizeof(float) * TALBLE_SIZE);
I was unable to find any equivalent for modern C++ but I may also have just missed it. Usually I would simply convert the pointer to a std::vector or std::array but this does not work when using memalign.
If std::array is an option for you, it's easy to align (same applies to bare arrays):
alignas(32) std::array<TALBLE_SIZE, float> table;
The standard function for dynamically allocating over-aligned memory inherited from C is std::aligned_alloc. It's nearly identical to the non-standard memalign; only difference is that it's stricter in requiring the size to be a multiple of the alignment. A pure C++ option is to use the operator new with std::align_val_t operand which will by default use std::aligned_alloc.
It's not a good idea to use the bare pointer returned by the allocation function though: You should use RAII. One option is to use std::vector with an allocator that uses over-aligned allocation function. Standard library doesn't provide such allocator though, so a custom one needs to be used. A more straightforward but less flexible option is to use std::unique_ptr with a deleter that calls std::free (or operator delete in case you had used operator new).
The code returns a TABLE_SIZE array of floats, the address would be aligned to 32 bytes.
malloc would have used the default alignment, which normally means double size alignment (but can be larger, implementation dependent).
For an array of floats - normal allocation and alignment is sufficient.
You would use memalign or the c++ aligned_alloc or posix_memalign to return a non regular alignment.
For instance, when using SSE or other SIMD extensions, that may require larger memory alignment than the default one.
My advice is to read the code, see if memory alignment is indeed needed, and either lose it for a normal allocation or move to std::aligned_alloc if it is really required.
The use of the literal 32 is suspicious in my opinion.

Why does the delete[] syntax exist in C++?

Every time somebody asks a question about delete[] on here, there is always a pretty general "that's how C++ does it, use delete[]" kind of response. Coming from a vanilla C background what I don't understand is why there needs to be a different invocation at all.
With malloc()/free() your options are to get a pointer to a contiguous block of memory and to free a block of contiguous memory. Something in implementation land comes along and knows what size the block you allocated was based on the base address, for when you have to free it.
There is no function free_array(). I've seen some crazy theories on other questions tangentially related to this, such as calling delete ptr will only free the top of the array, not the whole array. Or the more correct, it is not defined by the implementation. And sure... if this was the first version of C++ and you made a weird design choice that makes sense. But why with $PRESENT_YEAR's standard of C++ has it not been overloaded???
It seems to be the only extra bit that C++ adds is going through the array and calling destructors, and I think maybe this is the crux of it, and it literally is using a separate function to save us a single runtime length lookup, or nullptr at end of the list in exchange for torturing every new C++ programmer or programmer who had a fuzzy day and forgot that there is a different reserve word.
Can someone please clarify once and for all if there is a reason besides "that's what the standard says and nobody questions it"?
Objects in C++ often have destructors that need to run at the end of their lifetime. delete[] makes sure the destructors of each element of the array are called. But doing this has unspecified overhead, while delete does not. This is why there are two forms of delete expressions. One for arrays, which pays the overhead and one for single objects which does not.
In order to only have one version, an implementation would need a mechanism for tracking extra information about every pointer. But one of the founding principles of C++ is that the user shouldn't be forced to pay a cost that they don't absolutely have to.
Always delete what you new and always delete[] what you new[]. But in modern C++, new and new[] are generally not used anymore. Use std::make_unique, std::make_shared, std::vector or other more expressive and safer alternatives.
Basically, malloc and free allocate memory, and new and delete create and destroy objects. So you have to know what the objects are.
To elaborate on the unspecified overhead François Andrieux's answer mentions, you can see my answer on this question in which I examined what does a specific implementation do (Visual C++ 2013, 32-bit). Other implementations may or may not do a similar thing.
In case the new[] was used with an array of objects with a non-trivial destructor, what it did was allocating 4 bytes more, and returning the pointer shifted by 4 bytes ahead, so when delete[] wants to know how many objects are there, it takes the pointer, shifts it 4 bytes prior, and takes the number at that address and treats it as the number of objects stored there. It then calls a destructor on each object (the size of the object is known from the type of the pointer passed). Then, in order to release the exact address, it passes the address that was 4 bytes prior to the passed address.
On this implementation, passing an array allocated with new[] to a regular delete results in calling a single destructor, of the first element, followed by passing the wrong address to the deallocation function, corrupting the heap. Don't do it!
Something not mentioned in the other (all good) answers is that the root cause of this is that arrays - inherited from C - have never been a "first-class" thing in C++.
They have primitive C semantics and do not have C++ semantics, and therefore C++ compiler and runtime support, which would let you or the compiler runtime systems do useful things with pointers to them.
In fact, they're so unsupported by C++ that a pointer to an array of things looks just like a pointer to a single thing. That, in particular, would not happen if arrays were proper parts of the language - even as part of a library, like string or vector.
This wart on the C++ language happened because of this heritage from C. And it remains part of the language - even though we now have std::array for fixed-length arrays and (have always had) std::vector for variable-length arrays - largely for purposes of compatibility: Being able to call out from C++ to operating system APIs and to libraries written in other languages using C-language interop.
And ... because there are truckloads of books and websites and classrooms out there teaching arrays very early in their C++ pedagogy, because of a) being able to write useful/interesting examples early on that do in fact call OS APIs, and of course because of the awesome power of b) "that's the way we've always done it".
Generally, C++ compilers and their associated runtimes build on top of the platform's C runtime. In particular in this case the C memory manager.
The C memory manager allows you to free a block of memory without knowing its size, but there is no standard way to get the size of the block from the runtime and there is no guarantee that the block that was actually allocated is exactly the size you requested. It may well be larger.
Thus the block size stored by the C memory manager can't usefully be used to enable higher-level functionality. If higher-level functionality needs information on the size of the allocation then it must store it itself. (And C++ delete[] does need this for types with destructors, to run them for every element.)
C++ also has an attitude of "you only pay for what you use", storing an extra length field for every allocation (separate from the underlying allocator's bookkeeping) would not fit well with this attitude.
Since the normal way to represent an array of unknown (at compile time) size in C and C++ is with a pointer to its first element, there is no way the compiler can distinguish between a single object allocation and an array allocation based on the type system. So it leaves it up to the programmer to distinguish.
The cover story is that delete is required because of C++'s relationship with C.
The new operator can make a dynamically allocated object of almost any object type.
But, due to the C heritage, a pointer to an object type is ambiguous between two abstractions:
being the location of a single object, and
being the base of a dynamic array.
The delete versus delete[] situation just follows from that.
However, that's does not ring true, because, in spite of the above observations being true, a single delete operator could be used. It does not logically follow that two operators are required.
Here is informal proof. The new T operator invocation (single object case) could implicitly behave as if it were new T[1]. So that is to say, every new could always allocate an array. When no array syntax is mentioned, it could be implicit that an array of [1] will be allocated. Then, there would just have to exist a single delete which behaves like today's delete[].
Why isn't that design followed?
I think it boils down to the usual: it's a goat that was sacrificed to the gods of efficiency. When you allocate an array with new [], extra storage is allocated for meta-data to keep track of the number of elements, so that delete [] can know how many elements need to be iterated for destruction. When you allocate a single object with new, no such meta-data is required. The object can be constructed directly in the memory which comes from the underlying allocator without any extra header.
It's a part of "don't pay for what you don't use" in terms of run-time costs. If you're allocating single objects, you don't have to "pay" for any representational overhead in those objects to deal with the possibility that any dynamic object referenced by pointer might be an array. However, you are burdened with the responsibility of encoding that information in the way you allocate the object with the array new and subsequently delete it.
An example might help. When you allocate a C-style array of objects, those objects may have their own destructor that needs to be called. The delete operator does not do that. It works on container objects, but not C-style arrays. You need delete[] for them.
Here is an example:
#include <iostream>
#include <stdlib.h>
#include <string>
using std::cerr;
using std::cout;
using std::endl;
class silly_string : private std::string {
public:
silly_string(const char* const s) :
std::string(s) {}
~silly_string() {
cout.flush();
cerr << "Deleting \"" << *this << "\"."
<< endl;
// The destructor of the base class is now implicitly invoked.
}
friend std::ostream& operator<< ( std::ostream&, const silly_string& );
};
std::ostream& operator<< ( std::ostream& out, const silly_string& s )
{
return out << static_cast<const std::string>(s);
}
int main()
{
constexpr size_t nwords = 2;
silly_string *const words = new silly_string[nwords]{
"hello,",
"world!" };
cout << words[0] << ' '
<< words[1] << '\n';
delete[] words;
return EXIT_SUCCESS;
}
That test program explicitly instruments the destructor calls. It’s obviously a contrived example. For one thing, a program does not need to free memory immediately before it terminates and releases all its resources. But it does demonstrate what happens and in what order.
Some compilers, such as clang++, are smart enough to warn you if you leave out the [] in delete[] words;, but if you force it to compile the buggy code anyway, you get heap corruption.
Delete is an operator that destroys array and non-array(pointer) objects which are generated by new expression.
It can be used by either using the Delete operator or Delete [ ] operator
A new operator is used for dynamic memory allocation which puts variables on heap memory.
This means the Delete operator deallocates memory from the heap.
Pointer to object is not destroyed, value or memory block pointed by the pointer is destroyed.
The delete operator has a void return type that does not return a value.

What's the difference between using a variable to define array size and using the new operator c++?

I'm learning the basics of C++ with previous experience in Java based upon the official tutorial at "http://www.cplusplus.com/doc/tutorial/dynamic/". The tutorial presents the operator "new" as a way to define a array's size at runtime; however, this feels like a useless addition, since I can easily just define an array's size with a variable by doing
int numbers [size];
in contrast to
int * numbers = new int [size];
By testing on my own I already realized that using the new operator allows for going over the pre-allocated memory size (I could write to numbers[7] when I initialized it with size = 5), whereas the first line of code does not. I have three basic questions about this operator:
What's the difference between the two lines of code above?
Is it dangerous to write to a pointer address in memory in the array I didn't allocate to start with?
If it is dangerous to do so, what alternative could I use (if there is one) to setting up lists other than manually setting up (or using a library for) a linked list?
int numbers [size];
in contrast to
int * numbers = new int [size];
The first, in standard C++, requires the value of size to be known and fixed at compile time. The second allows the value of size to be determined at run time (e.g. based on user input).
Some compilers allow the first form to be used with size as a variable, but that is not standard C++. Such variable length arrays are a feature of C (from 1999) that some C++ compilers support as a non-standard extension. Other C++ compilers will diagnose an error (as required by the C++ standard).
How the first is allocated depends on context. For example;
If outside a function (e.g. at file scope) it will be allocated statically, and will exist for as long as the program runs.
If inside a block (e.g. in a function) arr will have automatic storage duration and will cease to exist at the end of enclosing block (e.g. when the function returns).
If a member of a struct or class type, the array will be created whenever an instance of that struct or class is created.
The first two above are, somewhat incorrectly, sometimes said to be created on "the stack". However, the C++ standard does not require that - "the stack" is an implementation detail associated with operating systems and runtime environment.
The second is said to allocate memory dynamically (using operator new). The memory will exist until it is explicitly released (e.g. using the corresponding operator delete).
Is it dangerous to write to a pointer address in memory in the array I didn't allocate to start with?
Yes. The behaviour is undefined by the C++ standard. Practically, it can seem to work correctly. It can also have unwanted effects, such as poisoning data used by your program or reformatting your hard drive. In nasty cases, it can seem to work correctly in your testing, only to have one of the unwanted effects when run by a paying client. Such occurrences tend to make for grumpy clients.
The behaviour is equally undefined whether working with a pointer or an array. Assigning a value to the tenth element of an array with five elements gives undefined behaviour, regardless of how the array is created (e.g. in either of your two options).
If it is dangerous to do so, what alternative could I use (if there is one) to setting up lists other than manually setting up (or using a library for) a linked list?
In C++, there are standard containers. Look up vector (in the standard header <vector>) for an example. Obviously it is possible to use a standard container incorrectly (and get unwanted effects) but it is easier to avoid problems using a standard container than it is with arrays or pointers.
Standard containers also handle memory allocation and deallocation automatically - there is no need for you, as the programmer, to manage dynamic memory directly (e.g. forgetting to release the memory when no longer needed).
What's the difference between the two lines of code above?
Assuming size is a constant expression, the difference is the first example is allocated on stack while the second on heap and you need to remember to delete [] it.
Is it dangerous to write to a pointer address in memory in the array I
didn't allocate to start with?
It's undefined behaviour to write outside bounds, but if you're within bounds you're ok:
constexpr int size = 5;
int arr[size];
arr[0] = 2;
If it is dangerous to do so, what alternative could I use
Use a std::vector:
std::vector<int> arr;
What's the difference between the two lines of code above?
The difference is that the first one is not allowed in C++. Some compilers will allow it and may give a warning when special flags are supplied, whereas other compilers retch at the sight of it).
The second one is the way to go and pretty much does the same thing no matter what compiler you use.
Is it dangerous to write to a pointer address in memory in the array I
didn't allocate to start with?
Yes it is. The behavior is undefined. If you don't get any exception at runtime, don't take that as a good thing because sooner than later, something will break surprisingly.
If it is dangerous to do so, what alternative could I use (if there is
one) to setting up lists other than manually setting up (or using a
library for) a linked list?
Are you asking for an alternative way to access memory that does not belong to you? The answer is DON'T DO IT!.
You can use one of C++'s containers as an alternative to creating a list of stuff. For a builtin linked list data structure, use std::list or std::forward_list. For random access containers, std::vector is a great start, but if you know the size ahead of time (i.e. before runtime), then std::array is the way to go.

Is reusing a memory location safe?

This question is based on some existing C code ported to C++. I am just interested in whether it is "safe". I already know I wouldn't have written it like this. I am aware that the code here is basically C rather than C++ but it's compiled with a C++ compiler and I know that the standards are slightly different sometimes.
I have a function that allocates some memory. I cast the returned void* to an int* and start using it.
Later on I cast the returned void* to a Data* and start using that.
Is this safe in C++?
Example :-
void* data = malloc(10000);
int* data_i = (int*)data;
*data_i = 123;
printf("%d\n", *data_i);
Data* data_d = (Data*)data;
data_d->value = 456;
printf("%d\n", data_d->value);
I never read variables used via a different type than they were stored but worry that the compiler might see that data_i and data_d are different types and so cannot legally alias each other and decide to reorder my code, for example putting the store to data_d before the first printf. Which would break everything.
However this is a pattern that is used all the time. If you insert a free and malloc in between the two accesses I don't believe it alters anything as it doesn't touch the affected memory itself and can reuse the same data.
Is my code broken or is it "correct"?
It's "OK", it works as you have written it (assuming primitives and plain-old-datatypes (PODs)). It is safe. It is effectively a custom memory manager.
Some notes:
If objects with non-trivial destructors are created in the location of the allocated memory, make sure it is called
obj->~obj();
If creating objects, consider the placement new syntax over a plain cast (works with PODs as well)
Object* obj = new (data) Object();
Check for a nullptr (or NULL), if malloc fails, NULL is returned
Alignment shouldn't a problem, but always be aware of it when creating a memory manager and make sure that the alignment is appropriate
Given you are using a C++ compiler, unless you want to keep the "C" nature to the code you can also look to the global operator new().
And as always, once done don't forget the free() (or delete if using new)
You mention that you are not going to convert any of the code just yet; but if or when you do consider it, there are a few idiomatic features in C++ you may wish to use over the malloc or even the global ::operator new.
You should look to the smart pointer std::unique_ptr<> or std::shared_ptr<> and allow them to take care of the memory management issues.
Depending on the definition of Data, your code might be broken. It's bad code, either way.
If Data is a plain old data type (POD, i.e. a typedef for a basic type, a struct of POD types etc.), and the allocated memory is properly aligned for the type (*), then your code is well-defined, which means it will "work" (as long as you initialize each member of *data_d before using it), but it is not good practice. (See below.)
If Data is a non-POD type, you are heading for trouble: The pointer assignment would not have invoked any constructors, for example. data_d, which is of type "pointer to Data", would effectively be lying because it points at something, but that something is not of type Data because no such type has been created / constructed / initialized. Undefined behaviour will be not far off at that point.
The solution for properly constructing an object at a given memory location is called placement new:
Data * data_d = new (data) Data();
This instructs the compiler to construct a Data object at the location data. This will work for POD and non-POD types alike. You will also need to call the destructor (data_d->~Data()) to make sure it is run before deleteing the memory.
Take good care to never mix the allocation / release functions. Whatever you malloc() needs to be free()d, what is allocated with new needs delete, and if you new [] you have to delete []. Any other combination is UB.
In any case, using "naked" pointers for memory ownership is discouraged in C++. You should either
put new in a constructor and the corresponding delete in the destructor of a class, making the object the owner of the memory (including proper deallocation when the object goes out of scope, e.g. in the case of an exception); or
use a smart pointer which effectively does the above for you.
(*): Implementations are known to define "extended" types, the alignment requirements of which are not taken into account by malloc(). I'm not sure if language lawyers would still call them "POD", actually. MSVC, for example, does 8-byte alignment on malloc() but defines the SSE extended type __m128 as having a 16-byte alignment requirement.
The rules surrounding strict aliasing can be quite tricky.
An example of strict aliasing is:
int a = 0;
float* f = reinterpret_cast<float*>(&a);
f = 0.3;
printf("%d", a);
This is a strict aliasing violation because:
the lifetime of the variables (and their use) overlap
they are interpreting the same piece of memory through two different "lenses"
If you are not doing both at the same time, then your code does not violate strict aliasing.
In C++, the lifetime of an object starts when the constructor ends and stops when the destructor starts.
In the case of built-in types (no destructor) or PODs (trivial destructor), the rule is instead that their lifetime ends whenever the memory is either overwritten or freed.
Note: this is specifically to support writing memory managers; after all malloc is written in C and operator new is written in C++ and they are explicitly allowed to pool memory.
I specifically used lenses instead of types because the rule is a bit more difficult.
C++ generally use nominal typing: if two types have a different name, they are different. If you access a value of dynamic type T as if it were a U, then you are violating aliasing.
There are a number of exceptions to this rule:
access by base class
in PODs, access as a pointer to the first attribute
And the most complicated rule is related to union where C++ shifts to structural typing: you can access a piece of memory through two different types, if you only access parts at the beginning of this piece of memory in which the two types share a common initial sequence.
§9.2/18 If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them. Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.
Given:
struct A { int a; };
struct B: A { char c; double d; };
struct C { int a; char c; char* z; };
Within a union X { B b; C c; }; you can access x.b.a, x.b.c and x.c.a, x.c.c at the same time; however accessing x.b.d (respectively x.c.z) is a violation of aliasing if the currently stored type is not B (respectively not C).
Note: informally, structural typing is like mapping down the type to a tuple of its fields (flattening them).
Note: char* is specifically exempt from this rule, you can view any piece of memory through char*.
In your case, without the definition of Data I cannot say whether the "lenses" rule could be violated, however since you are:
overwriting memory with Data before accessing it through Data*
not accessing it through int* afterwards
then you are compliant with the lifetime rule, and thus there is no aliasing taking place as far as the language is concerned.
As long as the memory is used for only one thing at a time it's safe. You're basically use the allocated data as a union.
If you want to use the memory for instances of classes and not only simple C-style structures or data-types, you have to remember to do placement new to "allocate" the objects, as this will actually call the constructor of the object. The destructor you have to call explicitly when you're done with the object, you can't delete it.
As long as you only handle "C"-types, this would be ok. But as soon as you use C++ classes you will get into trouble with proper initialization. If we assume that Data would be std::string for example, the code would be very wrong.
The compiler cannot really move the store across the call to printf, because that is a visible side effect. The result has to be as if the side effects are produced in the order the program prescribes.
Effectively, you've implemented your own allocator on top of malloc/free that reuses a block in this case. That's perfectly safe. Allocator wrappers can certainly reuse blocks so long as the block is big enough and comes from a source that guarantees sufficient alignment (and malloc does).
As long a Data remains a POD this should be fine. Otherwise you would have to switch to placement new.
I would however put a static assert in place so that this doesn't change during later refactoring
I don't find any mistake in reusing the memory space. Only what I care for is the dangling reference. Reusing memory space as you have said I think it doesn't have any effect on the program.
You can go on with your programming. But it is always preferable to free() the space and then allocate to another variable.

Why [] is used in delete ( delete [] ) to free dynamically allocated array ?

I know that when delete [] will cause destruction for all array elements and then releases the memory.
I initially thought that compiler wants it just to call destructor for all elements in the array, but I have also a counter - argument for that which is:
Heap memory allocator must know the size of bytes allocated and using sizeof(Type) its possible to find no of elements and to call appropriate no of destructors for an array to prevent resource leaks.
So my assumption is correct or not and please clear my doubt on it.
So I am not getting the usage of [] in delete [] ?
Scott Meyers says in his Effective C++ book: Item 5: Use the same form in corresponding uses of new and delete.
The big question for delete is this: how many objects reside in the memory being deleted? The answer to that determines how many destructors must be called.
Does the pointer being deleted point to a single object or to an array of objects? The only way for delete to know is for you to tell it. If you don't use brackets in your use of delete, delete assumes a single object is pointed to.
Also, the memory allocator might allocate more space that required to store your objects and in this case dividing the size of the memory block returned by the size of each object won't work.
Depending on the platform, the _msize (windows), malloc_usable_size (linux) or malloc_size (osx) functions will tell you the real length of the block that was allocated. This information can be exploited when designing growing containers.
Another reason why it won't work is that Foo* foo = new Foo[10] calls operator new[] to allocate the memory. Then delete [] foo; calls operator delete[] to deallocate the memory. As those operators can be overloaded, you have to adhere to the convention otherwise delete foo; calls operator delete which may have an incompatible implementation with operator delete []. It's a matter of semantics, not just keeping track of the number of allocated object to later issue the right number of destructor calls.
See also:
[16.14] After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?
Short answer: Magic.
Long answer: The run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the pointer, p. There are two popular techniques that do this. Both these techniques are in use by commercial-grade compilers, both have tradeoffs, and neither is perfect. These techniques are:
Over-allocate the array and put n just to the left of the first Fred object.
Use an associative array with p as the key and n as the value.
EDIT: after having read #AndreyT comments, I dug into my copy of Stroustrup's "The Design and Evolution of C++" and excerpted the following:
How do we ensure that an array is correctly deleted? In particular, how do we ensure that the destructor is called for all elements of an array?
...
Plain delete isn't required to handle both individual objects an arrays. This avoids complicating the common case of allocating and deallocating individual objects. It also avoids encumbering individual objects with information necessary for array deallocation.
An intermediate version of delete[] required the programmer to specify the number of elements of the array.
...
That proved too error prone, so the burden of keeping track of the number of elements was placed on the implementation instead.
As #Marcus mentioned, the rational may have been "you don't pay for what you don't use".
EDIT2:
In "The C++ Programming Language, 3rd edition", §10.4.7, Bjarne Stroustrup writes:
Exactly how arrays and individual objects are allocated is implementation-dependent. Therefore, different implementations will react differently to incorrect uses of the delete and delete[] operators. In simple and uninteresting cases like the previous one, a compiler can detect the problem, but generally something nasty will happen at run time.
The special destruction operator for arrays, delete[], isn’t logically necessary. However, suppose the implementation of the free store had been required to hold sufficient information for every object to tell if it was an individual or an array. The user could have been relieved of a burden, but that obligation would have imposed significant time and space overheads on some C++ implementations.
The main reason why it was decided to keep separate delete and delete[] is that these two entities are not as similar as it might seem at the first sight. For a naive observer they might seem to be almost the same: just destruct and deallocate, with the only difference in the potential number of objects to process. In reality, the difference is much more significant.
The most important difference between the two is that delete might perform polymorphic deletion of objects, i.e. the static type of the object in question might be different from its dynamic type. delete[] on the other hand must deal with strictly non-polymorphic deletion of arrays. So, internally these two entities implement logic that is significantly different and non-intersecting between the two. Because of the possibility of polymorphic deletion, the functionality of delete is not even remotely the same as the functionality of delete[] on an array of 1 element, as a naive observer might incorrectly assume initially.
Contrary to the strange claims made in some other answers, it is, of course, perfectly possible to replace delete and delete[] with just a single construct that would branch at the very early stage, i.e. it would determine the type of the memory block (array or not) using the household information that would be stored by new/new[], and then jump to the appropriate functionality, equivalent to either delete or delete[]. However, this would be a rather poor design decision, since, once again, the functionality of the two is too different. Forcing both into a single construct would be akin to creating a Swiss Army Knife of a deallocation function. Also, in order to be able to tell an array from a non-array we'd have to introduce an additional piece of household information even into a single-object memory allocations done with plain new. This might easily result in notable memory overhead in single object allocations.
But, once again, the main reason here is the functional difference between delete and delete[]. These language entities possess only apparent skin-deep similarity that exists only at the level of naive specification ("destruct and free memory"), but once one gets to understand in detail what these entities really have to do one realizes that they are too different to be merged into one.
P.S. This is BTW one of the problems with the suggestion about sizeof(type) you made in the question. Because of the potentially polymorphic nature of delete, you don't know the type in delete, which is why you can't obtain any sizeof(type). There are more problems with this idea, but that one is already enough to explain why it won't fly.
The heap itself knows the size of allocated block - you only need the address. Look like free() works - you only pass the address and it frees memory.
The difference between delete (delete[]) and free() is that the former two first call the destructors, then free memory (possibly using free()). The problem is that delete[] also has only one argument - the address and having only that address it need to know the number of objects to run destructors on. So new[] uses som implementation-defined way of writing somewhere the number of elements - usually it prepends the array with the number of elements. Now delete[] will rely on that implementation-specific data to run destructors and then free memory (again, only using the block address).
delete[] just calls a different implementation (function);
There's no reason an allocator couldn't track it (in fact, it would be easy enough to write your own).
I don't know the reason they did not manage it, or the history of the implementation, if I were to guess: Many of these 'well, why wasn't this slightly simpler?' questions (in C++) came down to one or more of:
compatibility with C
performance
In this case, performance. Using delete vs delete[] is easy enough, I believe it could all be abstracted from the programmer and be reasonably fast (for general use). delete[] only requires only a few additional function calls and operations (omitting destructor calls), but that is per call to delete, and unnecessary because the programmer generally knows the type he/she is dealing with (if not, there's likely a bigger problem at hand). So it just avoids calling through the allocator. Additionally, these single allocations may not need to be tracked by the allocator in as much detail; Treating every allocation as an array would require additional entries for count for trivial allocations, so it is multiple levels of simple allocator implementation simplifications which are actually important for many people, considering it is a very low level domain.
This is more complicated.
The keyword and the convention to use it to delete an array was invented for the convenience of implementations, and some implementations do use it (I don't know which though. MS VC++ does not).
The convenience is this:
In all other cases, you know the exact size to be freed by other means. When you delete a single object, you can have the size from compile-time sizeof(). When you delete a polymorphic object by base pointer and you have a virtual destructor, you can have the size as a separate entry in vtbl. If you delete an array, how would you know the size of memory to be freed, unless you track it separately?
The special syntax would allow tracking such size only for an array - for instance, by putting it before the address that is returned to the user. This takes up additional resources and is not needed for non-arrays.