1

I'm working on a project that doesn't use exceptions, and should stay that way. I overloaded (overrid will be more correct maybe) new operator in order to use my own memory manager. In my memory manager, in case of a failure in allocation - NULL is being returned. Now altough new operator returned NULL, the constructor is being called and then I get a seg fault because I didn't have memory allocated. The functionalitty that I'd want is that if the new operator returned NULL, then the constructor shouldn't be called (and I will check afterwards if the object was successfuly initialized).

I want it to work something like this:

myObject = new object(...);
if (NULL == myObject)
    printf("error")
else
    do something

Thanks!

3
  • The operator new and operator new[] functions only allocate memory, it's the compiler which creates the code to call the possible constructor when you use the new operator. Returning a null pointer (nullptr or alternatively 0) is the correct behavior on failure. Commented Sep 24, 2015 at 11:58
  • new object(...) allocates memory and calls constructor. I want it to call constructor only if the allocation succeeded. I know about the nothrow option which is what I need, but how do I make something like this when overloading? Commented Sep 24, 2015 at 12:00
  • @JoachimPileborg Only if you declare your allocation function as non-throwing via noexcept or throw(), see [basic.stc.dynamic.allocation]p3 -- it is not clear to me if that's implied when disabling exceptions. Commented Sep 24, 2015 at 12:39

4 Answers 4

6

You need to invoke new (nothrow), something like this:

myObject* = new (std::nothrow) myObject(...);

Then, instead of overriding the regular operator new you need to override the one(s) that take std::nothrow_t. For more on that, see here: http://www.cplusplus.com/reference/new/nothrow/

The regular operator new without nothrow is not supposed to return null on failure, rather it should throw. Since you aren't allowed to throw, you cannot implement those operators (unless by calling abort() on failure or something similar).

Finally, it might help to completely disable exceptions during compilation. I would hope this sort of mistake would have been caught then (I'm not sure about this).

Sign up to request clarification or add additional context in comments.

6 Comments

This is not the only way to do it, especially if you're writing your own operator new. [basic.stc.dynamic.allocation]p3 "If an allocation function that has a non-throwing exception specification fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall indicate failure only by throwing an exception of a type that would match a handler of type std::bad_alloc."
@dyp: How is "an allocation function that has a non-throwing exception specification" different from the operator new that takes std::nothrow_t? It seems to me that the nothrow one is noexcept, and the "regular" one is not, so I'm not entirely sure what you're driving at.
std::nothrow_t is not an exception specification. Also, I have removed a reference in my quotation: after "non-throwing exception speficiation", [basic.stc.dynamic.allocation]p3 refers to [except.spec], which is the section about "Exception specifications". While you cannot replace the default operator new(size_t) with a noexcept one, you can write custom allocation functions for class types which are noexcept.
In C++03, the same paragraph was: "If an allocation function declared with an empty exception-specification (15.4), throw(), fails to allocate storage, it shall return a null pointer."
@user3445972 Please provide a Minimal, Complete, Verifiable Example. Here's an example of how to replace allocation and deallocation functions such that they can fail by returning a null pointer: coliru.stacked-crooked.com/a/dcb4aa772cdfd89e
|
1

Eventually the solution was to add 'throw()' at the end of the function decleration of new.

void* operator new (size_t size) throw()

Could be done in either in the regular new or new (nothrow). In my imlpementation adding it to the regular new caused the desired effect that any 'new' call will be able to return NULL upon failure.

There is also an option of using '--force_new_nothrow' flag in compilation.

more about both can be found here

Comments

1

I'm assuming you want provide a custom, class-specific allocation function and not overload the new operator in the global namespace.

tl;dr

Since C++11: Declare your custom operator new with noexcept and everything works fine.

void* T::operator new (size_t size) noexcept;

Full answer

While the currently accepted answer given by John proposes a working solution, it implies that the std::nothrow tag is necessary and this can't be done without it, which is wrong.

This answer is just the (correct) comment of @dyp, expanded into a full answer and with current quotes from the standard.

The C++11 standard says in [basic.stc.dynamic.allocation], paragraph 3:

If an allocation function declared with a non-throwing exception-specification (15.4) fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall indicate failure only by throwing an exception of a type that would match a handler (15.3) of type std::bad_alloc (18.6.2.1).

Over the years, this sentence has been rewritten, but something semantically equivalent has been in C++14, C++17 and C++20. The current working draft for C++23 has this paragraph in [basic.stc.dynamic.allocation]:

An allocation function that has a non-throwing exception specification (14.5) indicates failure by returning a null pointer value. Any other allocation function never returns a null pointer value and indicates failure only by throwing an exception (14.2) of a type that would match a handler (14.4) of type std::bad_alloc (17.6.4.1).

The "non-throwing exception specification" is defined in [except.spec]. A function has this specification if you add noexcept as a suffix to the declaration. Thus, the code given in the question can work totally fine, but the custom new operator has to be declared with noexcept:

void* T::operator new (size_t size) noexcept;

Alternatively, up to C++17, using throw() instead of noexcept worked too, but it has been deprecated in C++11 and removed in C++20. It was the way to go before C++11. OP ended up using this according to their own answer.

Comments

0

You will have to do this by hand, ie.

object * create_object(MemoryManager & mem, ...) {
   void * chunk = mem.get_memory_for_object();
   if (chunk == NULL) return NULL;
   return new (chunk) object(...); // inplace new 
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.