I have the following C++ code:
int main(){
unsigned char *abc = (unsigned char *)calloc(100,1);
unsigned char *def = &abc[50];
delete def;
}
Would this deallocate all the memory allocated by the call to calloc, or just the memory starting at the memory location where def points to?
It is undefined behavior. A crash, if you are lucky.
According to C++ standard (Working Draft, N3291=11-0061)
3.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]
...
The value of the
first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation
function is one supplied in the standard library, the call has no effect. Otherwise, the behavior is undefined
if the value supplied to operator delete(void*) in the standard library is not one of the values returned
by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, constvstd::nothrow_t&) in the standard library ...
There are several problems here. First, you should use free if you used calloc.
Then, you should pass to free the same pointer you got from calloc.
calloc allocates memory as one continuous block, and the entire block gets deallocated with free, not a part of it.
See http://www.cplusplus.com/reference/cstdlib/calloc/.
delete can only delete memory allocated with new.
for memory allocated with calloc deallocate it using free.
and no, you can't just use a pointer to somewhere inside the allocated memory.
in C++, deal with simple character strings by using std::string from the <string> header.
it takes care of memory management for you.
It wouldn't necessarily deallocate anything as it has undefined behavior. You can only call delete on a pointer which was allocated with new. Not only was the memory allocated with calloc instead of new, but you are also not passing a pointer to what calloc returned, but to some other position within that block of memory.
Isn't *abc undefined there? delete def; wouldn't do anything if there is nothing to delete!
Related
I have following piece of code.
char* p = malloc(10);
p = p + 1;
free(p);
In above code,
How does malloc return the memory address when call malloc(10)?
How many bytes will be deallocated with free(p)?
How does free() know how many bytes to be deallocated?
As the man page for free will tell you, any argument except a pointer returned from malloc has undefined behaviour:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed
Regarding how free knows the size of the block: a typical memory allocator implementation has a header for each block (containing size, freelist pointers, etc.) and free knows the size of this header and the offset from the pointer returned by malloc.
This also answers your first question: malloc allocates such a block and returns a pointer to the start of the actual object.
Using the std::realloc function:
If the new size is smaller, does it always have warranty to keep the memory block on the same position and only make it smaller, or it can move sometimes the whole block?
The reason to ask this, is that we'are writing a large and very hard code, and it is useful to make read only all the variables we need to leave unchanged, to obtain compiler's errors, when we try to change the wrong variable.
#include<cstdlib>
#include<iostream>
using namespace std;
int main(){
//From 10,000,000 unsigned ints to 10 unsigned ints
unsigned int * const array=new unsigned int[10000000];
cout<<array<<endl;
realloc(array,10*sizeof(unsigned int));
cout<<array<<endl;
delete array;
return 0;
}
Although I agree with the other answers in that you should not depend on it, there is an answer to be found in the glibc source. (I am assuming that you are using glibc, as you have not (yet) answered my comment asking which C library you are using)
EDIT: Using realloc on memory allocated by new is indeed disallowed, as other answers have mentioned.
Memory allocated without internally using mmap
If a block of memory is not allocated with mmap, __libc_realloc calls the _int_realloc function, which contains the following snippet of code:
if ((unsigned long) (oldsize) >= (unsigned long) (nb))
{
/* already big enough; split below */
newp = oldp;
newsize = oldsize;
}
This makes the pointer to the new memory equal the pointer to the old memory and sets the size accordingly. Note the split below comment; the old memory block may be resized to the requested size, but is not moved.
Memory allocated internally using mmap
If the memory was internally allocated using mmap, there are two ways of resizing the memory area; mremap_chunk or a series of calls to malloc, memcpy and free. If the mremap_chunk function is available, it is used instead of the latter option.
Memory reallocated using mremap_chunk
The function mremap_chunk contains this snippet of code
/* No need to remap if the number of pages does not change. */
if (size + offset == new_size)
return p;
If the number of pages does not change from the old size to the new size, there is no need to remap and the old pointer is returned.
Memory reallocated using malloc, memcpy and free
If mremap_chunk is not available, the __libc_realloc source continues with the following:
/* Note the extra SIZE_SZ overhead. */
if (oldsize - SIZE_SZ >= nb)
return oldmem; /* do nothing */
If the oldsize variable minus the chunk size is more than or equal to the new size, just return the old memory.
Well then, here we are. In all cases, glibc returns a pointer to the old memory, not moving it (but possibly resizing it). If you are using glibc (and can somehow guarantee that the only C library you are using it with is glibc, and can guarantee that it won't change at some point in the future), you are able to rely on the behavior that realloc does not move a block of memory if the requested size is equal to or less than the old size.
No!! If realloc succeeds, the old pointer (unless it was a nullpointer) is indeterminate.
Also, do not mix incompatible memory-management-functions (assume incompatibility unless guaranteed otherwise).
realloc only has the guarantees explicitly given in the standard:
If return-value is non-0: New pointer points to of at least size byte, the first min(oldsize, newsize) being equal to the passed block.
Else if size is non-0, nothing happened to the passed block.
Else the old block may have been deallocated, or not.
Moral: Never pass a 0 size to realloc, and only use the old pointer for anything (including comparison to the new pointer), if realloc failed (or you passed a nullpointer).
7.22.3.5 The realloc function
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
2 The realloc function deallocates the old object pointed to by ptr and returns a
pointer to a new object that has the size specified by size. The contents of the new
object shall be the same as that of the old object prior to deallocation, up to the lesser of
the new and old sizes. Any bytes in the new object beyond the size of the old object have
indeterminate values.
3 If ptr is a null pointer, the realloc function behaves like the malloc function for the
specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory
management function, or if the space has been deallocated by a call to the free or
realloc function, the behavior is undefined. If memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Returns
4 The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
C99 draft 7.20.3.4 says:
[#4] The realloc function returns a pointer to the new
object (which may have the same value as a pointer to the
old object), or a null pointer if the new object could not
be allocated.
You should not assume it.
And also: don't mix new and realloc as πάντα already wrote in the comments.
Nothing's guaranteed about realloc. It might shrink the block in place, or it might allocate a new one and copy the data. It might also fail.
An important point: realloc is only for reallocating memory that was previously allocated by malloc. In your code above, you are using new which has no equivalent for reallocation.
Also realloc actually returns the address of the new memory block, so in your code above you will be a) leaking this and b) referencing/freeing potentially already de-allocated memory.
Lets say I allocate an array of ints
int test[] = new int[100];
I take a pointer to somewhere in the middle
int *temp = &test[50];
Then I call delete[] on the temp
delete[] temp
How will the compiler know the size of elements to delete in this case?
It won't (or will, I don't know). You're invoking undefined behavior. You're only allowed to call delete[] on a pointer allocated with new[].
For example, I get a crash in MSVS.
You have to pass the same memory location which was returned by new[], passing anything else is undefined behavior.
You cannot do that. A compiler has to keep track of the size of memory that it allocates. The standard does not say how it must to this. Some compilers store the size of the allocated memory just before the returned address. In such cases what you're doing can lead to undefined behavior.
The answer is no.
Because delete operator need to locate the location of the memory block and it's size, which is mostly ahead the first member of the allocated array.
you should have a look at the "Inside c++ object model"
The function may move the memory block to a new location, in which case the new location is returned.
For example I have a pointer to an array:
int *arr; // somewhere next it initialized, filled with elements and etc
Somewhere I need to:
void* location = realloc(arr, NEW_SIZE);
What will happen with old memory block place?
If realloc return pointer that not math to arr, should i use next code?:
delete arr;
arr = (int*)location;
The function realloc is inherited from good old C. It does not run destructors or do any other C++ magic. It can also only be applied to blocks allocated using malloc (and friends) -- it can not be used for blocks allocated using 'new'.
Rule #1: dont mix new/delete with malloc/free.
If you're allocating with malloc() in the first place and you need a bigger heap space then you need to call realloc() which will return you a new pointer which may not map to the same memory areas as arr therefore you should not use it.
Free malloc'ed/realloc'ed space with free
realloc(void *ptr, size_t new_size) requires the given area of memory that ptr points to to be previously allocated by malloc(), calloc() or realloc() and not yet freed with free(), otherwise, the results are undefined.
Use realloc only with malloc, calloc or another realloc and clean it up with free.
In C++ use always new with delete and new[] with delete[].
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...