Related
I know that stack allocation takes constant time. From what I understand, this happens because the allocation size can be determined in compile time. In this case the program knows how much memory is needed to run (for example) a function and the entire chunk of memory that is needed can be allocated at once.
What happens in cases where the allocation size is only known at run time?
Consider this code snippet,
void func(){
int n;
std::cin >> n;
// this is a static allocation and its size is only known at run time
int arr[n];
}
Edit: I'm using g++ 5.4 on linux and this code compiles and runs.
What happens in cases where the allocation size is only known at run time?
Then the program is ill-formed, and therefore compilers are not required to compile the program.
If a compiler does compile it, then it is up to the compiler to decide what happens (other than issuing a diagnostic message, as required by the standard). This is usually called a "language extension". What probably happens is: amount of memory is allocated for the array, determined by the runtime argument. More details may be available in the documentation of the compiler.
It is impossible (using standard C++ language) to allocate space on the stack without knowing how much space to allocate.
The line int arr[n]; is not a valid C++ code. It only compiles because the compiler you are using decided to let you do that, so for more information you should refer to your compiler documentation.
For GCC, you might take a look at this page: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
I'm using g++ 5.4 on linux and this code compiles and runs.
Yes, and this invalid code compiles under MSVC 2010:
int& u = 0;
The standard sais that this code is ill formed. Yet MSVC compiles it! This is because of a compiler extension.
GCC accepts it because it implements it as an extension.
When compiling with -pedantic-errors, GCC will reject the code correctly.
Likewise, MSVC has the /permissive- compiler argument to disable some of it's extensions.
The memory allocation procedure varies when the size to be allocated is determined at runtime. Instead of allocation on stack, memory is reserved on the heap when the size is not known at compile time. Now allocation of memory is possible on the heap until the main memory of the computer is completely used up. Also, in some languages like C,C++ the allocation is permanent and the user is required to deallocate the memory after use.
In the example given above, memory of size n*sizeof(int) is reserved on the heap and is garbage collected (in java or python) or manually deallocated if the memory is assigned a pointer. (in c/c++)
I'm trying to make sure an object gets aligned before I add it to a vector data structure. Responding to a warning C4316: 'Basic' : object allocated on the heap may not be aligned 16 warning, I have the following for the Basic object:
class Basic
{
public:
Basic();
~Basic();
};
It's a standard object here. Next, a unique_ptr to a new instance of Basic is allocated for the benefits of doing so. (as opposed to a standard pointer)
unique_ptr<Basic> e_Basic{new Basic()};
And I attempted to align the data, so that I can avoid alignment issues later on:
e_Basic.reset =_aligned_malloc((size_t)sizeof(Basic), (size_t)(16 + (sizeof(Basic) % 16))); //Verify alignment.
Finally adding the pointer to the vector array.
LocalBasicQueue.push_back(move(e_Basic));
The compiler says that it is kosher, but my "What the fudge?" code sense is going off. Would this result in a pointer to (Surely) aligned code?
Is it ok to declare(e_Basic.reset) equal to a pointer [as returned by _aligned_malloc()] in this fashion and call its unique_ptr<>, having the new pointer assigned?
There are a few problems with that code.
You allocate, construct, and then immediately destroy a Basic object for no reason.
You never initialize a Basic object in the memory allocated by _aligned_malloc.
By default unique_ptr will release the memory it manages with delete, but you didn't new that memory, you _aligned_malloced it. This is a Bad Idea, and will likely result in heap corruption and/or crashes.
You can remedy the first problem simply by not initializing your unique_ptr with a new Basic().
The second can be fixed using a placement new expression.
The third can be fixed by giving the unique_ptr a custom deleter that calls ~Basic and _aligned_free instead of delete Note though that a unique_ptr<Basic, my_deleter> is a different type than unique_ptr<Basic>, so you can't put that into a vector<unique_ptr<Basic>>.
The second and third problems can also be fixed by overloading Basic::operator new and Basic::operator delete to use _aligned_malloc and _aligned_delete respectively, but that will mean that new Basic() always uses _aligned_malloc, which you may or may not want.
I am trying to figure out who are the components or modules (maybe belong to the OS?) that actually do the stuff when application or a process is running and specifically run the command delete[] X.
My question came up after I read about delete[] X and I understand that the compiler is responsible (according its implementation) to know how many objects of X to delete. But, the compiler is not "active" at runtime! I mean, at compile time, the compiler does not know how many memory the user need in a new command so, nor it does at delete, so what actually happened at run time when the program actually running?
One of the answers I read about was something called run-time system, what is it? is it connected to the CPU - because the CPU executes the command eventually... or maybe the OS?
Another answer I saw said it "is done by the system's allocator" (How does delete[] know how much memory to delete?) - again where is this component (OS, CPU)?
The compiler is responsible to generate code that deletes it when the need arises. It doesn't need to be running when it happens. The generated code will probably be a function call to a routine that does something along these lines:
void delete_arr(object *ptr)
{
size_t *actual_start = ((size_t *)ptr) - 1;
int count = *actual_start;
for (int i = count-1; i >= 0; i--)
destruct(ptr[i]);
free(actual_start);
}
When new[] is called, it actually saved the number of elements next to the allocated memory. When you call delete[] it looks up the number count and then deletes that number of elements.
The library that provides these facilities, is called the C++ standard library or the C++ runtime environment. The standard doesn't say anything about what constitutes a runtime, so definitions might differ, but the gist is it's what's need to support running C++ code.
C++ runtime is (indirectly) using Operating System primitives to change the virtual address space of the process running your program.
Read more about computer architecture, CPU modes, operating systems, OS kernels, system calls, instruction sets, machine code, object code, linkers, relocation, name mangling, compilers, virtual memory.
On my Linux system, new (provided by the C++ standard library) is generally built above malloc(3) (provided by the C standard library) which may call the mmap(2) system call (implemented inside the kernel) which changes the virtual address space (by dealing with the MMU). And delete (from C++ standard library) is generally built above free(3) which may call munmap(2) system call which changes the virtual address space.
Things are much more complex in the details:
new is calling the constructor after having allocated memory with malloc
delete is calling the destructor before releasing memory with free
free usually mark the freed memory zone as reusable by future malloc (so usually don't release memory with munmap)
so malloc usually reuses previously freed memory zone before request more address space (using mmap) from the kernel
for array new[] and delete[], the memory zone contains the size of the array, and the constructor (new[]) or destructor (delete[]) is called in a loop
technically, when you code SomeClass*p = new SomeClass(12); the memory is first allocated using ::operator new (which calls malloc), and then the constructor of SomeClass is called with 12 as argument
when you code delete p;, the destructor of SomeClass is called and then the memory is released using ::operator delete (which calls free)
BTW, a Linux system is made of free software, so I strongly suggest you to install some Linux distribution on your machine and use it. So you can study the source code of libstdc++ (the standard C++ library, which is part of the GCC compiler source code but linked by your program), of libc (the standard C library), of the kernel. You could also strace(1) your C++ program and process to understand what system calls it is doing.
If using GCC, you can get the generated assembler code by compiling your foo.cc C++ source file with g++ -Wall -O -fverbose-asm -S foo.cc which produces the foo.s assembler file. You can also get some textual view of the intermediate Gimple internal representation inside the compiler with g++ -Wall -O -fdump-tree-gimple -c foo.cc (you'll get some foo.cc.*.gimple and perhaps many other GCC dump files). You could even search something inside the Gimple representation using the GCC MELT tool (I designed and implemented most of it; use g++ -fplugin=melt -fplugin-arg-melt-mode=findgimple).
The standard C++ library has internal invariants and conventions, and the C++ compiler is responsible to follow them when emitting assembler code. So the compiler and its standard C++ library are co-designed and written in close cooperation (and some dirty tricks inside your C++ library implementations require compiler support, perhaps thru compiler builtins etc...). This is not specific to C++: Ocaml folks also co-design and co-implement the Ocaml language and its standard library.
The C++ runtime system has conceptually several layers: the C++ standard library libstdc++, the C standard library libc, the operating system (and at the bottom the hardware, including the MMU). All these are implementation details, the C++11 language standard don't really mention them.
It might be helpfull
for each call to global ::operator new() it will take the object size passed and add the size of extra data
it will allocate a memory block of size deduced at previous step
it will offset the pointer to the part of the block not occupied with extra data and return that offset value to the caller
::operator delete() will do the same in reverse - shift the pointer,
access extra data, deallocate memory.
And usually delete [] uses when you delete an array of object allocated into the heap. As I know new [] also add extra data in the start of allocated memory in which it store information about size of array for delete [] operator. It also could be useful:
In other words, in general case a memory block allocated by new[] has two sets of extra bytes in front of the actual data: the block size in bytes (introduced by malloc) and the element count (introduced by new[]). The second one is optional, as your example demonstrates. The first one is typically always present, as it is unconditionally allocated by malloc. I.e. your malloc call will physically allocate more than 20 bytes even if you request only 20. These extra bytes will be used by malloc to store the block size in bytes.
...
"Extra bytes" requested by new[] from operator new[] are not used to "store the size of allocated memory", as you seem to believe. They are used to store the number of elements in the array, so that the delete[] will know how many destructors to call. In your example destructors are trivial. There's no need to call them. So, there's no need to allocate these extra bytes and store the element count.
It works in two stages. One is the compiler doing things that seem magical and then the heap doing things that also seem magical.
That is, until you realize the trick. Then the magic is gone.
But fist lets recap what happens when you do new X[12];
The code that the compiler writes under the cover conceptually looks like this:
void* data = malloc(12 * sizeof(X))
for (int i=0; i != 12; ++i) {
X::Ctor(data);
data += sizeof(X);
}
Where Ctor(void* this_ptr) is a secret function that sets the this pointer calls the constructor of X. In this case the default one.
So at destruction, we can undo this, if only we could stash the 12 somewhere easy to find ...
I am guessing you have guessed where already ...
Anyplace! really! for example, it could be store right before the start of the object.
the first line becomes these 3 lines:
void* data = malloc((12 * sizeof(X)) +sizeof(int));
*((int*)data) = 12;
data += sizeof(int);
The rest stays the same.
When the compiler sees delete [] addr it knows that 4 bytes before addr it can find the object count. It also needs to call free(addr - sizeof(int));
This is by the way in essence the same trick that malloc and free use. At least on the old days when we had simple allocators.
When you use the new keyword, a the program requests a block of memory from the OS on the heap to hold the object. A pointer to that memory space is returned. Without using new the compiler puts the object on the stack and during compile time the memory for those objects is aligned on the stack. Any object created using new needs to be deleted when there is no longer need for it so it is important that the original pointer to the heap block is not lost so you can call delete on it. When you use delete[] it will free all the blocks in an array. Example you use delete[] if you created char* anarray = new char[128] and you would use delete if you did string *str = new string() because a string is referred to as an object and char* is a pointer to an array.
Edit: some objects overload the delete operator so your object can support proper freeing of dynamic memory, so an object could be held responsible for determining the behavior of it
I came across an issue which I could not resolve.
My question is, if I used malloc to allocate memory and then memory block is delete using delete?
The general thumb rule is
If we allocate memory using malloc, it should be deleted using free.
If we allocate memory using new, it should be deleted using delete.
Now, in order to check what happens if we do the reverse, I wrote a small code.
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
class A
{
int p=10;
public:
int lol() {
return p;
}
};
int main()
{
int *a = (int *)malloc(sizeof(int)*5);
for(int i=0; i<4; i++) {
a[i] = i;
cout << a[i] << endl;
}
delete(a);
// Works fine till here..
A b;
cout << b.lol() << endl;
free(b); // Causes error.
return 0;
}
The error which I get is:
error: cannot convert ‘A’ to ‘void*’ for argument ‘1’ to ‘void
free(void*)’
I am unable to understand why is this happening. Please explain.
When you call delete a pointer, the compiler will call the dtor of the class for you automatically, but free won't. (Also new will call ctor of the class, malloc won't.)
In you example, a char array apparently don't have a dtor, so delete does nothing but return the memory. That's why it's okay. (Or vise versa, new a char array and then free it.)
But there can still be a problem: what if new and malloc are borrowing memory from different heap manager?
Imagine that, you borrow money from people A, and return to people B later. Even if you are okay with that, have you ever consider A's feeling?
BTW, you should use delete [] pArray; to free an array allocated using new[].
The free function expects a pointer to memory allocated by malloc. The compiler is simply telling you that did not pass it a pointer, a fact that it can readily prove. I guess you meant to create an object with new and then call free on the address of that object. But you did not call new.
When you correct this you may well find the free succeeds but you should not read anything significant into any such success. You know the rules, they are clearly stated in your documentation. It is incorrect to do what you are attempting. The behaviour is undefined. There's little to be gained from an experiment like this. You won't learn anything about why the C memory management functions cannot be paired with C++ memory management functions.
The problem with your experiment is that is has no power. You can just show the outcome for one specific scenario. But these functions are designed to work across the board. How are you going to test every single possible scenario?
Never program using trial and error. You must always understand the rules and priciples behind what you do.
Your b variable is not a pointer, but a stack-allocated A. If you want to try this experiment, then you'd want to say
A* b = new A;
free(b);
I'm all for experimentation, but I'm not sure what you were trying to achieve here.
In C++, operator new doesn't just allocate memory, it runs constructors too. Similarly, delete runs destructors for you (taking polymorphic classes into account), as well as freeing the returned memory. On the other hand, malloc() and free() are just C library routines which (from a programmer's point of view) do nothing more than request a chunk of memory from the operating system, and then hand it back.
Now, for a simple, POD class with trivial constructors and destructors, you might be able to get away with mixing up C and C++ memory allocation, because there's nothing C++-specific to be done. But even if you do, what does it prove? It's undefined behaviour, and it probably won't work on another compiler. It might not work tomorrow.
If you use any C++ features -- inheritance, virtual functions, etc etc, it very definitely won't work, because new and delete have to do a lot more work than just allocating memory.
So please, stick to the rules! :-)
You didn't create b using new so you are not testing the intended hypothesis. (Also, the name of b is not a pointer.)
Anyway, malloc/new and delete/free work interchangeably only as long as their implementations are interchangeable. In simple cases and on simpler platforms this is more likely, but it's a risky bet in the long term or as a habit.
For example, the array form of new, when applied to a class with a nontrivial destructor, requires the implementation (compiler, runtime, etc.) to remember the size of the array so that delete may call the destructor for each array object. There is almost nowhere to put such information but in the dynamically allocated block itself, preceding the memory location referred to by the pointer returned by new. Passing this pointer to free would then require the memory allocator to determine the actual start of the allocation block, which it may or may not be able to do.
More generally, new and malloc may refer to completely different memory allocators. The compiler, runtime library, and OS work together to provide memory to your program. The details can change as a result of switching or upgrading any of these components.
From the documentation,
void free (void* ptr);
ptr::
Pointer to a memory block previously allocated with malloc, calloc or
realloc.
And what you are passing is not a pointer, so it complains.
A *b = new A();
cout << b->lol() << endl;
free(b); // Will Not cause error
No, it is not a rule of thumb that you should not mix new/free or malloc/delete.
Sure, it might be possible to use free to relinquish an allocation you obtained with new without a crash, but it is highly implementation/system specific.
Ignoring the fact that you're bypassing destructors or writing code that will corrupt memory on some systems, the more fundamental, more basic C++ consideration is really simply this:
malloc/free are global, system functions, while new and delete are operators.
struct X {
void* operator new(size_t);
void operator delete(void* object);
};
Sure - you can borrow a book from Amazon and return it to your local library: go there late one night and leave it on their front door step.
It's going to have undefined behavior, up to and including your getting arrested - and I'm talking about mixing new/free again here :)
Put another way: malloc and free deal with raw memory allocations, while new and delete deal with objects, and that's a very different thing.
void* p = new std::vector<int>(100);
void* q = malloc(sizeof(*q));
Many good reasons have already been given. I'll add one more reason: the new operator can be overriden in c++. This allows the user to specify their own memory management model if they so desire. Although this is pretty uncommon, its existence is just one more reason why malloc and new, delete and free cannot be used interchangeably. This is for the reason described by #Patz.
free() accepts a pointer.
You are passing an object (not a pointe) to free. That is why you are getting the error. If you make below change, your code works fine.
A *a = new A;
free(a);
Though the code above works fine, it will lead to a memory leak because free() doesn't call the destructor, which is responsible for freeing the resource(s) created by the constructor.
I have been working on some legacy C++ code that uses variable length structures (TAPI), where the structure size will depend on variable length strings. The structures are allocated by casting array new thus:
STRUCT* pStruct = (STRUCT*)new BYTE[sizeof(STRUCT) + nPaddingSize];
Later on however the memory is freed using a delete call:
delete pStruct;
Will this mix of array new[] and non-array delete cause a memory leak or would it depend on the compiler? Would I be better off changing this code to use malloc and free instead?
Technically I believe it could cause a problem with mismatched allocators, though in practice I don't know of any compiler that would not do the right thing with this example.
More importantly if STRUCT where to have (or ever be given) a destructor then it would invoke the destructor without having invoked the corresponding constructor.
Of course, if you know where pStruct came from why not just cast it on delete to match the allocation:
delete [] (BYTE*) pStruct;
I personally think you'd be better off using std::vector to manage your memory, so you don't need the delete.
std::vector<BYTE> backing(sizeof(STRUCT) + nPaddingSize);
STRUCT* pStruct = (STRUCT*)(&backing[0]);
Once backing leaves scope, your pStruct is no longer valid.
Or, you can use:
boost::scoped_array<BYTE> backing(new BYTE[sizeof(STRUCT) + nPaddingSize]);
STRUCT* pStruct = (STRUCT*)backing.get();
Or boost::shared_array if you need to move ownership around.
Yes it will cause a memory leak.
See this except from C++ Gotchas: http://www.informit.com/articles/article.aspx?p=30642 for why.
Raymond Chen has an explanation of how vector new and delete differ from the scalar versions under the covers for the Microsoft compiler... Here:
http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx
IMHO you should fix the delete to:
delete [] pStruct;
rather than switching to malloc/free, if only because it's a simpler change to make without making mistakes ;)
And, of course, the simpler to make change that I show above is wrong due to the casting in the original allocation, it should be
delete [] reinterpret_cast<BYTE *>(pStruct);
so, I guess it's probably as easy to switch to malloc/free after all ;)
The behaviour of the code is undefined. You may be lucky (or not) and it may work with your compiler, but really that's not correct code. There's two problems with it:
The delete should be an array delete [].
The delete should be called on a pointer to the same type as the type allocated.
So to be entirely correct, you want to be doing something like this:
delete [] (BYTE*)(pStruct);
The C++ standard clearly states:
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
The first alternative is for non-array objects, and the second is for arrays. The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type. The result has type void.
In the first alternative (delete object), the value of the operand of delete shall be a pointer to a non-array object [...] If not, the behavior is undefined.
The value of the operand in delete pStruct is a pointer to an array of char, independent of its static type (STRUCT*). Therefore, any discussion of memory leaks is quite pointless, because the code is ill-formed, and a C++ compiler is not required to produce a sensible executable in this case.
It could leak memory, it could not, or it could do anything up to crashing your system. Indeed, a C++ implementation with which I tested your code aborts the program execution at the point of the delete expression.
As highlighted in other posts:
1) Calls to new/delete allocate memory and may call constructors/destructors (C++ '03 5.3.4/5.3.5)
2) Mixing array/non-array versions of new and delete is undefined behaviour. (C++ '03 5.3.5/4)
Looking at the source it appears that someone did a search and replace for malloc and free and the above is the result. C++ does have a direct replacement for these functions, and that is to call the allocation functions for new and delete directly:
STRUCT* pStruct = (STRUCT*)::operator new (sizeof(STRUCT) + nPaddingSize);
// ...
pStruct->~STRUCT (); // Call STRUCT destructor
::operator delete (pStruct);
If the constructor for STRUCT should be called, then you could consider allocating the memory and then use placement new:
BYTE * pByteData = new BYTE[sizeof(STRUCT) + nPaddingSize];
STRUCT * pStruct = new (pByteData) STRUCT ();
// ...
pStruct->~STRUCT ();
delete[] pByteData;
#eric - Thanks for the comments. You keep saying something though, that drives me nuts:
Those run-time libraries handle the
memory management calls to the OS in a
OS independent consistent syntax and
those run-time libraries are
responsible for making malloc and new
work consistently between OSes such as
Linux, Windows, Solaris, AIX, etc....
This is not true. The compiler writer provides the implementation of the std libraries, for instance, and they are absolutely free to implement those in an OS dependent way. They're free, for instance, to make one giant call to malloc, and then manage memory within the block however they wish.
Compatibility is provided because the API of std, etc. is the same - not because the run-time libraries all turn around and call the exact same OS calls.
The various possible uses of the keywords new and delete seem to create a fair amount of confusion. There are always two stages to constructing dynamic objects in C++: the allocation of the raw memory and the construction of the new object in the allocated memory area. On the other side of the object lifetime there is the destruction of the object and the deallocation of the memory location where the object resided.
Frequently these two steps are performed by a single C++ statement.
MyObject* ObjPtr = new MyObject;
//...
delete MyObject;
Instead of the above you can use the C++ raw memory allocation functions operator new and operator delete and explicit construction (via placement new) and destruction to perform the equivalent steps.
void* MemoryPtr = ::operator new( sizeof(MyObject) );
MyObject* ObjPtr = new (MemoryPtr) MyObject;
// ...
ObjPtr->~MyObject();
::operator delete( MemoryPtr );
Notice how there is no casting involved, and only one type of object is constructed in the allocated memory area. Using something like new char[N] as a way to allocate raw memory is technically incorrect as, logically, char objects are created in the newly allocated memory. I don't know of any situation where it doesn't 'just work' but it blurs the distinction between raw memory allocation and object creation so I advise against it.
In this particular case, there is no gain to be had by separating out the two steps of delete but you do need to manually control the initial allocation. The above code works in the 'everything working' scenario but it will leak the raw memory in the case where the constructor of MyObject throws an exception. While this could be caught and solved with an exception handler at the point of allocation it is probably neater to provide a custom operator new so that the complete construction can be handled by a placement new expression.
class MyObject
{
void* operator new( std::size_t rqsize, std::size_t padding )
{
return ::operator new( rqsize + padding );
}
// Usual (non-placement) delete
// We need to define this as our placement operator delete
// function happens to have one of the allowed signatures for
// a non-placement operator delete
void operator delete( void* p )
{
::operator delete( p );
}
// Placement operator delete
void operator delete( void* p, std::size_t )
{
::operator delete( p );
}
};
There are a couple of subtle points here. We define a class placement new so that we can allocate enough memory for the class instance plus some user specifiable padding. Because we do this we need to provide a matching placement delete so that if the memory allocation succeeds but the construction fails, the allocated memory is automatically deallocated. Unfortunately, the signature for our placement delete matches one of the two allowed signatures for non-placement delete so we need to provide the other form of non-placement delete so that our real placement delete is treated as a placement delete. (We could have got around this by adding an extra dummy parameter to both our placement new and placement delete, but this would have required extra work at all the calling sites.)
// Called in one step like so:
MyObject* ObjectPtr = new (padding) MyObject;
Using a single new expression we are now guaranteed that memory won't leak if any part of the new expression throws.
At the other end of the object lifetime, because we defined operator delete (even if we hadn't, the memory for the object originally came from global operator new in any case), the following is the correct way to destroy the dynamically created object.
delete ObjectPtr;
Summary!
Look no casts! operator new and operator delete deal with raw memory, placement new can construct objects in raw memory. An explicit cast from a void* to an object pointer is usually a sign of something logically wrong, even if it does 'just work'.
We've completely ignored new[] and delete[]. These variable size objects will not work in arrays in any case.
Placement new allows a new expression not to leak, the new expression still evaluates to a pointer to an object that needs destroying and memory that needs deallocating. Use of some type of smart pointer may help prevent other types of leak. On the plus side we've let a plain delete be the correct way to do this so most standard smart pointers will work.
If you really must do this sort of thing, you should probably call operator new directly:
STRUCT* pStruct = operator new(sizeof(STRUCT) + nPaddingSize);
I believe calling it this way avoids calling constructors/destructors.
I am currently unable to vote, but slicedlime's answer is preferable to Rob Walker's answer, since the problem has nothing to do with allocators or whether or not the STRUCT has a destructor.
Also note that the example code does not necessarily result in a memory leak - it's undefined behavior. Pretty much anything could happen (from nothing bad to a crash far, far away).
The example code results in undefined behavior, plain and simple. slicedlime's answer is direct and to the point (with the caveat that the word 'vector' should be changed to 'array' since vectors are an STL thing).
This kind of stuff is covered pretty well in the C++ FAQ (Sections 16.12, 16.13, and 16.14):
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.12
It's an array delete ([]) you're referring to, not a vector delete.
A vector is std::vector, and it takes care of deletion of its elements.
You'd could cast back to a BYTE * and the delete:
delete[] (BYTE*)pStruct;
Yes that may, since your allocating with new[] but deallocating with delelte, yes malloc/free is safer here, but in c++ you should not use them since they won't handle (de)constructors.
Also your code will call the deconstructor, but not the constructor. For some structs this may cause a memory leak (if the constructor allocated further memory, eg for a string)
Better would be to do it correctly, as this will also correctly call any constructors and deconstructors
STRUCT* pStruct = new STRUCT;
...
delete pStruct;
It's always best to keep acquisition/release of any resource as balanced as possible.
Although leaking or not is hard to say in this case. It depends on the compiler's implementation of the vector (de)allocation.
BYTE * pBytes = new BYTE [sizeof(STRUCT) + nPaddingSize];
STRUCT* pStruct = reinterpret_cast< STRUCT* > ( pBytes ) ;
// do stuff with pStruct
delete [] pBytes ;
Len: the problem with that is that pStruct is a STRUCT*, but the memory allocated is actually a BYTE[] of some unknown size. So delete[] pStruct will not de-allocate all of the allocated memory.
You're sort of mixing C and C++ ways of doing things. Why allocate more than the size of a STRUCT? Why not just "new STRUCT"? If you must do this then it might be clearer to use malloc and free in this case, since then you or other programmers might be a little less likely to make assumptions about the types and sizes of the allocated objects.
#Matt Cruikshank
You should pay attention and read what I wrote again because I never suggested not calling delete[] and just let the OS clean up. And you're wrong about the C++ run-time libraries managing the heap. If that were the case then C++ would not be portable as is today and a crashing application would never get cleaned up by the OS. (acknowledging there are OS specific run-times that make C/C++ appear non-portable). I challenge you to find stdlib.h in the Linux sources from kernel.org. The new keyword in C++ actually is talking to the same memory management routines as malloc.
The C++ run-time libraries make OS system calls and it's the OS that manages the heaps. You are partly correct in that the run-time libraries indicate when to release the memory however, they don't actually walk any heap tables directly. In other words, the runtime you link against does not add code to your application to walk heaps to allocate or deallocate. This is the case in Windows, Linux, Solaris, AIX, etc... It's also the reason you won't fine malloc in any Linux's kernel source nor will you find stdlib.h in Linux source. Understand these modern operating system have virtual memory managers that complicates things a bit further.
Ever wonder why you can make a call to malloc for 2G of RAM on a 1G box and still get back a valid memory pointer?
Memory management on x86 processors is managed within Kernel space using three tables. PAM (Page Allocation Table), PD (Page Directories) and PT (Page Tables). This is at the hardware level I'm speaking of. One of the things the OS memory manager does, not your C++ application, is to find out how much physical memory is installed on the box during boot with help of BIOS calls. The OS also handles exceptions such as when you try to access memory your application does not have rights too. (GPF General Protection Fault).
It may be that we are saying the same thing Matt, but I think you may be confusing the under hood functionality a bit. I use to maintain a C/C++ compiler for a living...
#ericmayo - cripes. Well, experimenting with VS2005, I can't get an honest leak out of scalar delete on memory that was made by vector new. I guess the compiler behavior is "undefined" here, is about the best defense I can muster.
You've got to admit though, it's a really lousy practice to do what the original poster said.
If that were the case then C++ would
not be portable as is today and a
crashing application would never get
cleaned up by the OS.
This logic doesn't really hold, though. My assertion is that a compiler's runtime can manage the memory within the memory blocks that the OS returns to it. This is how most virtual machines work, so your argument against portability in this case don't make much sense.
#Matt Cruikshank
"Well, experimenting with VS2005, I can't get an honest leak out of scalar delete on memory that was made by vector new. I guess the compiler behavior is "undefined" here, is about the best defense I can muster."
I disagree that it's a compiler behavior or even a compiler issue. The 'new' keyword gets compiled and linked, as you pointed out, to run-time libraries. Those run-time libraries handle the memory management calls to the OS in a OS independent consistent syntax and those run-time libraries are responsible for making malloc and new work consistently between OSes such as Linux, Windows, Solaris, AIX, etc.... This is the reason I mentioned the portability argument; an attempt to prove to you that the run-time does not actually manage memory either.
The OS manages memory.
The run-time libs interface to the OS.. On Windows, this is the virtual memory manager DLLs. This is why stdlib.h is implemented within the GLIB-C libraries and not the Linux kernel source; if GLIB-C is used on other OSes, it's implementation of malloc changes to make the correct OS calls. In VS, Borland, etc.. you will never find any libraries that ship with their compilers that actually manage memory either. You will, however, find OS specific definitions for malloc.
Since we have the source to Linux, you can go look at how malloc is implemented there. You will see that malloc is actually implemented in the GCC compiler which, in turn, basically makes two Linux system calls into the kernel to allocate memory. Never, malloc itself, actually managing memory!
And don't take it from me. Read the source code to Linux OS or you can see what K&R say about it... Here is a PDF link to the K&R on C.
http://www.oberon2005.ru/paper/kr_c.pdf
See near end of Page 149:
"Calls to malloc and free may occur in any order; malloc calls
upon the operating system to obtain more memory as necessary. These routines illustrate some of the considerations involved in writing machine-dependent code in a relatively machineindependent way, and also show a real-life application of structures, unions and typedef."
"You've got to admit though, it's a really lousy practice to do what the original poster said."
Oh, I don't disagree there. My point was that the original poster's code was not conducive of a memory leak. That's all I was saying. I didn't chime in on the best practice side of things. Since the code is calling delete, the memory is getting free up.
I agree, in your defense, if the original poster's code never exited or never made it to the delete call, that the code could have a memory leak but since he states that later on he sees the delete getting called. "Later on however the memory is freed using a delete call:"
Moreover, my reason for responding as I did was due to the OP's comment "variable length structures (TAPI), where the structure size will depend on variable length strings"
That comment sounded like he was questioning the dynamic nature of the allocations against the cast being made and was consequentially wondering if that would cause a memory leak. I was reading between the lines if you will ;).
In addition to the excellent answers above, I would also like to add:
If your code runs on linux or if you can compile it on linux then I would suggest running it through Valgrind. It is an excellent tool, among the myriad of useful warnings it produces it also will tell you when you allocate memory as an array and then free it as a non-array ( and vice-versa ).
Use operator new and delete:
struct STRUCT
{
void *operator new (size_t)
{
return new char [sizeof(STRUCT) + nPaddingSize];
}
void operator delete (void *memory)
{
delete [] reinterpret_cast <char *> (memory);
}
};
void main()
{
STRUCT *s = new STRUCT;
delete s;
}
I think the is no memory leak.
STRUCT* pStruct = (STRUCT*)new BYTE [sizeof(STRUCT) + nPaddingSize];
This gets translated into a memory allocation call within the operating system upon which a pointer to that memory is returned. At the time memory is allocated, the size of sizeof(STRUCT) and the size of nPaddingSize would be known in order to fulfill any memory allocation requests against the underlying operating system.
So the memory that is allocated is "recorded" in the operating system's global memory allocation tables. Memory tables are indexed by their pointers. So in the corresponding call to delete, all memory that was originally allocated is free. (memory fragmentation a popular subject in this realm as well).
You see, the C/C++ compiler is not managing memory, the underlying operating system is.
I agree there are cleaner methods but the OP did say this was legacy code.
In short, I don't see a memory leak as the accepted answer believes there to be one.
Rob Walker reply is good.
Just small addition, if you don't have any constructor or/and distructors, so you basically need allocate and free a chunk of raw memory, consider using free/malloc pair.
ericmayo.myopenid.com is so wrong, that someone with enough reputation should downvote him.
The C or C++ runtime libraries are managing the heap which is given to it in blocks by the Operating System, somewhat like you indicate, Eric. But it is the responsibility of the developer to indicate to the compiler which runtime calls should be made to free memory, and possibly destruct the objects that are there. Vector delete (aka delete[]) is necessary in this case, in order for the C++ runtime to leave the heap in a valid state. The fact that when the PROCESS terminates, the OS is smart enough to deallocate the underlying memory blocks is not something that developers should rely on. This would be like never calling delete at all.