'new' issue

Started by
22 comments, last by loufoque 14 years, 10 months ago
From the beginning, I always used new pretty much like malloc with some extra machinery. Let me say that my 'beginning' means many years ago. At the time, exceptions were still somewhat clunky, and although they worked in theory, I have to say their implementation were terrible. So, new at the time just returned NULL on failure, which was fine to me at the time, although we all know how much the subsequent pointer checking is.

float *vec = new float[nComps * nvtx];
if(!vec) return false; // how boring
In 2009 I started to think that I could transition to the new exception-based new (which happens to be the standard even for MS libs now): after all, this is an excellent application for exceptions, which in the meanwhile have matured alot. So I started to drop the pointer checking. Today, I read: A call to new may return NULL if the platform has run out of memory, so test the return value before dereferencing it.. Uh-oh. So, is the throwing new standard or not? Is he referring non-PC platforms? I admit that I have no multiplatform experience at all and minimal multi-OS experience.

Previously "Krohm"

Advertisement
Yes, new should throw exception when it can not allocate requested memory
If you don't want for it to throw exception, then use nonthrowing new:
#include <new>...float* p = new (std::nothrow) float [count];

Yes, a throwing 'new' is standard C++ '98, though it took some years before Microsoft released a new C++ compiler after their, uhm, "groundbreaking" MSVC++ 6.0.

edit: ninja'd++.
Thank you both for your fast reply,
however, I am sort of unsure I am communicating correctly my concerns.

The non-throw'ing null is well known to me. It is not something I want to see around in my code. I actually don't want new to NOT throw exceptions, I want to migrate to the throwing null, which implies always valid pointers out of it.

And, yes, I know the throwing NULL is standard since years, as well as my refusal to use exceptions in most situations is probably not justified those days.

Yet the article I linked comes from a source I personally find trustable and if they write that new can still return NULL I am left wondering what they're talking about.

I have tens of thousands of line of code using NULL-new accumulated for reuse over the years. Although inelegant by my current likings, they will work with throwing NULL. It is forward compatible.
By contrast, the throwing null approach is not back compatible. Although the possibility I port to some esoteric or closed platform is minimal, I still like to believe it is not zero.
Now, in the admittedly low chance this happens, if the platform doesn't support throwing new, all this code will turn unsafe.
Seeying it in perspective, knowing that MSVC will play nice and that "it is standard since" ten years ago, leaves me at the start - I don't think this example was random.

Previously "Krohm"

Then, what exactly is your question if it's not

Quote:So, is the throwing new standard or not?


because a throwing new is standard. If new doesn't throw an exception upon out-of-memory, then that behaviour is compiler specific and non-standard. In that case, you must check the manual of the compiler you are going to use. Imho, it isn't worth the effort to take into account all possible compiler specifics until you use that compiler, and until you write a library. Fr instance, if you look at boost, you will see that they coded their library to be compatible to many compilers, and that lead to total code uglyness in some parts of their files.

If you ask me, yagni. The less you have to write, the less error prone is your code.

Out of curiosity: Does the guy say that "in C++, new can return NULL", or does he say "under the compiler foo, new can return NULL"? Because the former is false, and would have to be rephrased to the latter.
Since the article mentions programming for the Wii it's probably that they've turned off exceptions since they have a non-trivial amount of overhead. Given this it's probably that the compiler switches to no-throw new everywhere, or they're using a custom allocator which returns NULL instead of throwing an exception.
That was exactly my line of thinking. Thank you very much for confirming my fears were real.

I think I will just keep NULL-new convention for another couple of years.

Previously "Krohm"

Quote:Original post by Krohm

I think I will just keep NULL-new convention for another couple of years.


Stick with COBOL instead.

Quote:I admit that I have no multiplatform experience at all and minimal multi-OS experience.


For you - new is the standard and only way. It allows to progress beyond C and 15 years old concepts as well as use modern libraries (written in last 10 years).

Just because some project that you did not develop, that you have never worked with, that you don't plan to work on and that you will never encounter chose to not use exceptions (they serve no real use on Wii - if it breaks, console breaks), is not even remotely a legitimate reason to avoid something.

It gets even trickier. On systems with virtual memory, even if new succeeds, you are not guaranteed to have actually claimed the memory. Since large blocks do not get committed, it is perfectly possible to have new succeed, yet fail when accessing the memory on a new page when it is actually committed. See overcommit.

So if you want to be sure, you need to write custom allocator, that will write all allocated bytes, and then either return the pointer, or crash.

But since few have heard about this problem, it just goes to show how irrelevant allocation failures have become on every desktop OS.

And if you are working on system with limited memory, the whole process becomes completely different anyway, so null will be the least of your worries.
Just for reference, from TC++PL §6.2.6.2 "Memory Exhaustion":
Quote:
What happens when new can find no store to allocate? By default, the allocator throws a bad_alloc exception [...]

I could not find anything in the standard after a few minutes of searching. Anyone?
float *vec = new float[nComps * nvtx];


If you do something like this, your code probably isn't exception safe in the first place - if new indeed did throw somewhere, you'd leak memory from all the other naked pointers that you might have around. (Or you'll need to handle the exception very close to the source, which would be quite tedious too.)

std::vector<float> vec(nComps * nvtx);


Leak-proof now.

This topic is closed to new replies.

Advertisement