Home > OS >  Deleting an object constructed without new (C )
Deleting an object constructed without new (C )

Time:01-22

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:

  1. 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.
  2. If mem was allocated on the heap without an appropriate new:

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.

  • Related