views:

116

answers:

3

I have the following code, which doesn't compile:

int *p = new(nothrow) int;
delete (nothrow) p; //Error

The error I get is:

error C2440: 'delete' : cannot convert from 'const std::nothrow_t' to 'void*'

Does a nothrow version of delete exist? If so, how can I invoke it?


In C++: The Complete Reference, it's given that it exists but I saw different opinions online, hence the confusion.

MSDN also talks about its existence, but I couldn't find how it can be used in code.

Here, some people are saying that there is no such thing.

+5  A: 

There is no such form of delete, because delete does not throw, since:

  1. It performs no allocations.
  2. It's often used in destructors which should not throw!

Items created with the nothrow version of new, will return NULL instead of throwing a bad_alloc exception. Using delete on NULL is perfectly valid, so there is no situation where it should throw.

Michael Goldshteyn
@Michael: Oh. But in complete reference c++ book, its given that it exists and i saw different different opinions in internet, hence the confusion.
bjskishore123
@Michael: What do you mean "they were not allocated from the heap"? It still allocates memory, it just won't throw if it can't.
GMan
Sorry, updated to be less confusing and not confuse with in-place new...
Michael Goldshteyn
This answer is still wrong, or at least ambiguous. There is no `delete` expression that can call `operator delete(..., std::nothrow)`, but that operator still exists.
GMan
+2  A: 

For most practical purposes, there's only one version of delete. The new(nothrow) is written as a placement new operator, but for the most part, there's no corresponding version for delete. The only exception to that is a version of delete that gets invoked when a placement new throws -- but since (in this case) you've assured that the new can't throw, that version of delete is of no real use/help here.

Jerry Coffin
+9  A: 

A std::nothrow_t deallocation function exists, but you cannot call it with a delete expression.

The deallocation function is there for completeness. If a new expression fails because of an exception, the compiler needs to free the memory it allocated via operator new with a matching call to operator delete. So there needs to be an operator delete that accepts a std::nothrow_t, to allow this.

(That is, in general, a new expression with the form new (args...) T will allocate memory with a call to operator new(sizeof(T), args...). To "match" means to call operator delete with the same arguments, except the first.)

Note you can call the operator directly: operator delete(memory, std::nothrow);. However, a delete expression never calls a global deallocation function with additional parameters.


So you can "call" it with:

struct always_throw
{
    always_throw() { throw std::exception(); }
};

new (std::nothrow) always_throw;

At some point, this will allocate memory with a call to:

void* __memory = operator new(sizeof(always_throw), std::nothrow);

Since the initialization of the object throws, the compiler needs to free the allocated memory with a matching deallocation function, so it does:

operator delete(__memory, std::nothrow);

Calling the std::nothrow_t version.

GMan
so, does compiler invoke nothrow version of delete internally, even if user calls normal version of delete ?
bjskishore123
@bjskishore: Nope. I've edited that in.
GMan