3

When using new and a bad_alloc exception is thrown. Do you still need to call delete on the ptr before carrying on or can you be confident that no memory has been allocated?

How about if you use the nothrow version? can you again be confident that no memory has been allocated if a nullptr is returned?

uhsl_m
  • 322
  • 3
  • 11
  • Which "ptr" are you talking about? Post some code. – Kerrek SB Jan 19 '17 at 10:12
  • any ptr that is being allocated memory via new – uhsl_m Jan 19 '17 at 10:17
  • Post. Some. Code. The first part of the question is unanswerable as written, and borderline nonsensical. When `new` throws, the expression evaluation did not complete. – Kerrek SB Jan 19 '17 at 10:17
  • Thank you, that is the answer. I want to make sure I can be confident that no allocation has occurred. The question was indeed that simple. – uhsl_m Jan 19 '17 at 10:23

2 Answers2

3

When an exception is thrown, you don't "carry on" - execution jumps to the catch handler.

In an expression like:

p = new int;

the sub-expression new int is evaluated first. If that throws an exception then execution does not reach the assignment. p retains the previous value it had (if any).

In the case p = new(std::nothrow) int; then if allocation fails, p will become a null pointer. It has no effect to invoke delete on a null pointer.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • No its not. You answered it. I was asking if you can be confident that no assignment has occurred and/or no memory has been allocated. – uhsl_m Jan 19 '17 at 10:19
2

The nothrow version of new does indeed report errors by returning a null pointer, in which case no memory has been allocated and no object has been constructed:

T * p = new (std::nothrow) T(a, b, c);

if (p)
{
    // stuff
}

delete p;   // OK, works on null pointers, too.

Or maybe:

if (T * p = new (std::nothrow) T(a, b, c))
{
    // stuff
    delete p;
}
else
{
    // allocation failure
}

Or even better:

if (std::unique_ptr<T> p(new (std::nothrow) T(a, b, c)))
{
    // stuff
}

The last version automatically deletes the dynamic object on any exit from the if block, which is a typical example of C++'s way of handling multiple exits and thus localizing complexity.

(Maybe there should be a make_unique_or_null function template to encapsulate this last bit.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Of course, second example has the problem of memory leak if `// stuff` can throw – M.M Jan 19 '17 at 10:17
  • @M.M: The first example has that problem, too. I assume you generally know about the need for exception-correct code. – Kerrek SB Jan 19 '17 at 10:19
  • 1
    Yeah, I think it would be good if your answer mentions this at some stage in case it is not clear to beginner what the advantage of the last version is – M.M Jan 19 '17 at 10:20
  • I would assume your try catch would be within `//stuff` and before the delete to handle that if there is also a possibility `//stuff` could throw. – uhsl_m Jan 19 '17 at 10:21
  • @M.M: I think that's a red herring. The last version supports multiple exits, and the first two don't. Exceptions are just one small part of the concern of multiple exits, and you generally have to understand how to structure control flow. I think that's a little beyond the scope of this question...? – Kerrek SB Jan 19 '17 at 10:22