In the context of the OP - what do you use - malloc or new ?
It depends entirely on what I (the OP, if I were) need it *for*,
actually. If all I need is a block of memory that's guaranteed to be
aligned and at least N chars large, malloc fits the bill perfectly.
If I need to create N objects, malloc obviously won't do and I need to
use new. If I need the returned memory to be of a specific type, I'm
very likely better off using new, though using malloc and casting the
return is acceptable for POD types. There are plenty of reasons to
use new in preference to malloc. The portability of malloc isn't one
of them.
Since the OP did not supply any context for his question on why
someone might prefer one over the other, the most appropriate answer
from this group is probably "it depends," though the other answers
given were mostly excellent. The various differences that are topical
here have been well covered.
IIRC, the reason why I ended up knowing about issues with free(0) and
malloc(0) was when my own malloc library did different things than the
standard library
....for your compiler and platform...
and code started to break everywhere. It became clear to me that wether
I liked it or not, malloc(0) should likely return non-null otherwise
lots of code broke. It was used in some cases as a process specific
unique number generator.
This is a usage not well-supported by malloc; while you can use it
that way, the standard only guarantees that IF malloc(n) returns a non-
NULL pointer at all, THEN that pointer will not be returned by malloc
again until passed to free. It does not guarantee that it will return
a non-NULL pointer at all, either for n = 0 or any other value of n.
In some cases strings of 0 length were allocated and
comparison of string pointer was an identifying mark of being the same
string. My initial work around for the "malloc bug" was to change the
length to 1 if it came in as zero but later I fixed the code so the
allocated block was actually 0 bytes long.
You may argue all you like about how portable malloc is but in reality I
have had alot of experience that tells me differently.
Take a moment to consider the Newsgroups: header on this post, and the
topic area of the newsgroups listed there. The original question, and
all subsequent discussion, is mostly being taken in the context of the
standard C++ programming language, not any specific implementation.
Had I been reading, say, comp.os.linux.development, I would've
immediately turned to the man page on malloc and the g++ standard
library documentation to consider quirks of the usual C and C++
libraries available under Linux before getting involved.
malloc(0) just leads to novices creating code that may or may not be
portable. That's the only thing I was alluding to.
The behaviour of incorrect code, no matter who wrote it, is outside
the scope of the C++ language, and the C language.
By experience it is true. The C standard can say all it likes but
broken code exists and new broken code will continue to be written.
If you wish to discuss implementation-specific behaviour, there are
places for exactly that. comp.lang.c++ is rarely one of them.
Because compilers are deterministic, you can very likely derive the
exact expected behaviour for any given bit of "invalid" code under a
specific compiler by reading that compiler's documentation or
experimenting with that compiler's output.
What standard ? I wrote code in this thread earlier that works on one
platform and not on another - wether it's conforming or not is
irrelevant, the fact is that I know it exists because I ran into 10s of
applications that expected certain behaviour from malloc(0). It's proof
by existence.
Actually, from the point of view of the C++ programming language, the
code you wrote works perfectly under both outcomes. It just doesn't
do what you want it to under one of them. I realize that sounds like
semantic niggling, but "works" is a very vague term, whereas "has well-
defined results" isn't.
I'm aware that you're using a definition of "works" that means "the
constructor completes without an exception." However, the code you've
written does not necessarily do that. If you want that behaviour, you
have to program for it yourself. This is not because of a flaw in
malloc; it is because of a difference between the code you wrote and
the code you intended to write. A bug, in other words, for which
you've already been offered a solution. Similar instances of bad
assumptions in code outside your control should be taken up with that
code's author.
The same behaviour is permitted from new (and new[]). Nothing in the C
++ standard demands that a new-expression exhaust memory before
throwing std::bad_alloc -- in fact, the definition of new and new[] is
carefully written to allow malloc() as an allocator function[0].
Therefore, nothing prohibits a compliant C++ implementation from, by
default, throwing bad_alloc consistently on either of the two
following examples:
....
int main () {
int *i = new int[0]; // Here
I don't think any C++ compiler will throw here either (I have yet to see
one) unless memory is exhausted (by some implementation defined meaning
of ehausted).
A lack of proof that this can happen is not a proof that this can't
happen.
Absolutely. I don't mean that any serious implementation would have
glaring flaws like that.
Do you know of the existance of a platform that will consistantly throw
bad_alloc for "int *i = new int[0];" ?
No. Nor do I assume it will never happen, except by accident.
What are standards for again ?
In this case, to define what behaviour is mandatory and what is up to
each implementation. You're asserting that, because some
implementations make use of the leeway the standard gives them, even
though that leeway is well-signposted for the language's users and has
very clear boundaries, it somehow weakens the portability of code that
takes those implementation-defined areas under consideration.
That's one of the side effects of standards.
No OS I know of acts as though bound by a mere language specification,
nor do hardware vendors design their chips and boards first with C
programmers in mind and second with the real task. It's up to the
language implementors for each platform to make their implementation
conform to the standard (which on the whole they do), not up to the
language standard to force each platform to conform it.
What the committee wants to do is highly dependent of the committee
members. However, given that one of the most critical features of a
computer language like C and C++ is to have a certain degree of code
portability, I would expect that this one would be high on it's priority
list.
In my experience it is a high priority. In my experience code that
remains within the bounds of the C++ specification and which makes no
unwarranted assumptions *is* highly portable. Code that makes invalid
assumptions is, to varying degrees, less portable; it's a necessary
price to pay for allowing implementations to support things outside
the C++ standard.
Frankly, once you're into dynamic memory management, you're well into
portability Bat Country no matter how tidy the language is. Here's a
poser for you: write a clear, unambiguous specification for a function
much like malloc which takes a size and returns a pointer to a memory
block at least that large that is not circular in any way and does not
contain an out like C's "implementation-defined behaviour." I tried;
every attempt eventually became circular or involved dragging in
specific environmental features like memory managers.
Even Java doesn't guarantee that "new byte[0];" at the beginning of
execution will succeed, only that if it does succeed it will return a
reference to a 0-element byte array -- exactly the same guarantee made
by C++, and exactly the same guarantee made by C for malloc (0).
Sigh. True. I have met too many programmers to know reality is
unfortunately different. The best thing is for the standards committee
to provide well defined behaviour where there is no compelling
implementation dependent reason to do otherwise. i.e. malloc(0) being
defined to behave like malloc(1) would have been a fine requirement in
the standard.
It is defined like malloc(1). The clause about malloc(0) being
permitted to do either of two things applies equally well to malloc(n)
for all n in size_t. It is a warning that some implementations are
going to break a particularly common but bad assumption more often for
0 than for other values, and nothing more.
As it happens, I've written code that makes all sorts of invalid
assumptions about standard library functions. When it eventually
crashed, I had to learn how and why my assumptions were wrong, which
meant reading both the specification and the documentation for the
implementation. Frequently, it also meant reading the implementation
itself.
Writing correct code that does what you mean it to do is *hard*. C++
does not go out of its way to make it easy, favouring powerful
features over "safe" ones; consequently, incorrect code tends to be
*very* incorrect.