I came across an article on the new / operator new: https://eli.thegreenplace.net/2011/02/17/the-many-faces-of-operator-new-in-c
and couldn't understand the following example:
int main(int argc, const char* argv[])
{
char mem[sizeof(int)];
int* iptr2 = new (mem) int;
delete iptr2; // Whoops, segmentation fault!
return 0;
}
Here the memory for int wasn't allocated using new
, hence the segfault for delete
.
What exactly delete
doesn't like here? Is there some additional structure hidden when an object is initialized with new
, that it looks for?
Thank you.
EDIT: I'll take out of comments several responses which helped me to understand the situation better:
- As @463035818_is_not_a_number and @HolyBlackCat pointed out
mem
was allocated on the stack, while delete tries to free memory on the heap. It's a pretty clear cut error and should lead to a segfault on most architectures. - If
mem
was allocated on the heap without an appropriatenew
:
The only way to do it I know would be, say, to allocate an int* on a heap, then reinterpret_cast it to an array of chars and ask delete a char pointer. On a couple of architectures I tried this actually works, but leads to a memory leak. In general, C standard makes no guarantees in this case, because doing so would make binding assumption on the underlying architecture.
CodePudding user response:
delete
deletes objects from the heap. Your object is on the stack, not on the heap.
new
(new T
, not the placement-new you used) does two things: allocates heap memory (similar to malloc()
), then performs initialization (for classes, calls a constructor).
Placement-new
(what you used) performs initialization in existing memory, it doesn't allocate its own.
And delete
does two things: calls the destructor (for class types), then frees the heap memory (similar to free()
).
Since your object is not on the heap, delete
can't delete its memory.
There's no "placement-delete
" that only calls the destructor. Instead, we have manual destructor calls:
If you had a class type, you'd do iptr2->MyClass::~MyClass();
to call the destructor. And freeing the memory is then unnecessary since stack memory is automatically deallocated when leaving the current scope.
Also note that you forgot alignas(int)
on your char array.
CodePudding user response:
What exactly delete doesn't like here?
The fact that it was called for a pointer that did not come from a real new
.
Is there some additional structure hidden when an object is initialized with new, that it looks for?
That is a near certainty for your C implementation, but it's completely immaterial. This is undefined behavior, full stop. delete
is defined only for pointers to objects that were created with a non-placement new
operator. Otherwise this is undefined behavior. This is an important distinction. The "your C implementation" part is relevant. It's certainly possible that a different C compiler or operating system will produce code that doesn't crash, and does nothing at all. Or it may draw a funny face on your monitor screen. Or play a tune that you hate, on your speakers. This is what "undefined behavior" means. And in this case, "undefined behavior" means a crash, in your case.
CodePudding user response:
You can only delete
what has been allocated via new
.
As explained in the article, placement new, skips the allocation:
Calling placement new directly skips the first step of object allocation. We don't ask for memory from the OS. Rather, we tell it where there's memory to construct the object in [3]. The following code sample should clarify this:
You cannot delete
mem
because it has not been allocated via new
. mem
has automatic storage duration and gets freed when main
returns.
Placement new in your code creates an int
in already allocated memory. If int
had a destructor you would need to call the destructor (but not deallcoate the memory). Placing the int
in the memory of mem
does not change the fact that mem
is allocated on the stack.
Actually the placement new in the code is not that relevant for the issue in the code. Also this code
int main(int argc, const char* argv[])
{
char mem[sizeof(int)];
delete iptr2; // Whoops, Undefined
return 0;
}
Has undefined behavior just as your code has.
CodePudding user response:
There are several flavours of new
and delete
.
The (non-placement) new
operator allocates memory by calling the operator new()
function. The delete
operator frees memory by calling the operator delete()
function. They are a pair.
(Confused yet? Read this, or maybe this).
The new[]
operator allocates memory by calling the operator new[]()
function. The delete[]
operator frees memory by calling the operator delete[]()
function. They are a different pair.
The placement new
operator does not allocate memory and does not call any kind of operator new()
-like function. There is no corresponding delete
operator or operator delete()
-like function.
You cannot mix new
of one flavour with delete
of a different flavour, it makes no sense and the behaviour is undefined.