Using malloc in C++?

G

Gianni Mariani

Jack Klein wrote:
....
Replace the line above with:

if (len && !ptr)

You're ability to resolve this instance of problem is uncontested.

I bet you can't fix this problem in my source files without getting
access to them or changing the behaviour of malloc on all systems !
 
O

Owen Jacobson

Chinese fish prices not withstanding ?

That's what "implementation defined" means, yes. The entire behaviour
of malloc is, somewhat obliquely, implementation-defined. The only
properties malloc must have in a conforming implementation is always
producing any of a fixed set of outputs for any given input, and that
subsequent operations on those values also have predictable results.
I don't see the relevance of this to this thread. We're talking about
portability issues of malloc over new. Someone assered that malloc
behaves differently on different platforms. My recollection was that
free(0) and malloc(0) used to be poorly specified. Someone said that
malloc(0) has two standard behaviours and I said QED. How this relates
to code throwing exceptions is about as relevant as PRC fish prices.

The assertion that malloc is somehow "less portable" than new is so
wrong-headed that I thought I'd have a shot at dismantling it. Plus,
I like replying to you.
Reread what I wrote. If it's not nearly identical to what you assert
then I don't understand.

Ah, but your point, as I read it, was that malloc's behaviour when
passed 0 as an argument was somehow less well-specified than its
behaviour in the face of other inputs. This is, as supported by
careful examination of the C standard, not true. Code which relies on
malloc returning a non-NULL pointer, and code which relies on new
returning a pointer rather than throwing an exception, *must* be
prepared for the alternative as it will eventually happen in all but
the most trivial examples. Period.
Again this is relevant to this discussion how ? The "mystring" code I
hacked earlier is an example where on one platform malloc(0) returning
different values on different platforms causing vastly different things
to happen being a portability issue.

Neither the C nor the C++ standard guarantees that conforming code
will behave identically on all platforms. They guarantee that
conforming code will behave *predictably* on all conforming
platforms. This is true of all programming languages that have formal
definitions.
That's all. Code like this
exists. The point is that new has a more strict definition

Cite from the relevant standards? I don't see any evidence that
that's actually true.
and hence it will result in better code portability.

*If* 'new' has a more strict definition than malloc, then code that
utilises 'new' will have a more strictly-defined behaviour than code
that uses malloc, yes.
Again, so what ? The point is that code (bad or otherwise) exists such
that it works on one platform and not another because of THIS behaviour
of malloc which does not happen with new. That's all. If you think it
does not exist, see my code above. If you don't believe that anyone
would write code like that, get more experience.

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:

--example1.cpp--

class Empty {
};

int main () {
Empty *e = new Empty (); // Here

delete e;
}

--example2.cpp--

int main () {
int *i = new int[0]; // Here

delete i;
}

--end--

Once again, such an implementation would be conforming: the behaviour
of both programs is predictable. It would merely be extremely poor.
The standard does continue on to describe what appears to be a special
case for malloc(0): ....
However, on closer analysis both of these cases can be derived from
the general behaviour of malloc described elsewhere: 1. that
arithmetic on the returned pointer be limited to the half-open
interval [x, x+size), which is an empty interval when size is 0, and
2. that malloc may return NULL. Therefore this is not a special case,
and implementations that return NULL on malloc(0) even when memory is
available are merely poor implementations.

Poor but compliant making the fault that of the standard.

I find it hard to believe you expect the ISO standards committee to
control the behaviour of myriad implementation vendors, as that's what
enforcing any specific behaviour from a memory-allocation function
would require. It would also require absolute cooperation from OS
vendors and hardware manufacturers.
Sure. By that question do you imply you want me to do something about
it? You seem to have a grasp of the issue, you're just as qualified as
I am. Good luck with the C committee.

While I'm not psychic, I believe the C committee's goals to include
defining a language in which both extremely portable code and
extremely platform-dependant code may be written. Consequently, the
standard defines rules within which code is guaranteed to behave
predictably under any conforming implementation; it is up to
programmers to be familiar with these rules if they wish to write code
that's as portable as C allows. The language does not demand that all
code remain within these rules.

Owen

[0] The clause that demands that allocation functions return non-NULL
pointers on an argument of 0 bytes means that malloc may only be used
as a nothrow allocation function, which are allowed to return NULL to
indicate failure to allocate. Malloc may not be used as-is by an
implementation's default allocation function; however, this trivial
wrapper, as far as I can tell, may:

--trivial-malloc-wrapper.cpp--

#include <cctype>
#include <cstdlib>
#include <exception>

void *mallocator (std::size_t size) {
void *allocated = std::malloc (size);
if (!allocated) throw std::bad_alloc ();
return allocated;
}

--end--
 
O

Old Wolf

Dear Old. It's not the point. The point is portability.

Huh? Portable code is code that complies with
the standards. You can write portable code with
malloc, as evinced by the thousands of portable C
applications out there.

It seems you are criticizing malloc based on
a buggy code-snippet you wrote. I am saying
that it is not malloc being non-portable, it
is that your code has a bug.
 
O

Old Wolf

The point is that new has a more strict definition and hence it
will result in better code portability. It seems damn obvious to me,
why cant you see it.

Nobody else can see it either .. perhaps it's you that's wrong?

Firstly, new does not have a more strict definition.
malloc(0) has two options:
- return NULL
- return valid pointer

new T[0] has three options:
- throw exception
- return valid pointer
- return NULL, if T has a custom allocator (see 5.3.4/13)

So it seems to me that 'new' is LESS strictly specified than malloc.

Secondly, strict definition doesn't mean more portable.
In fact, C and C++ specifications were deliberately
made as non-strict as possible, to _improve_ portability.

It's no coincidence that C is available on almost every
single platform that has anything other than assembly.
 
G

Gianni Mariani

Owen said:
That's what "implementation defined" means, yes. The entire behaviour
of malloc is, somewhat obliquely, implementation-defined. The only
properties malloc must have in a conforming implementation is always
producing any of a fixed set of outputs for any given input, and that
subsequent operations on those values also have predictable results.

This describes malloc and numerous other interfaces. Again, so ? Here
is some more info http://www.fa.gov.tw/eng/news/news.php.
The assertion that malloc is somehow "less portable" than new is so
wrong-headed that I thought I'd have a shot at dismantling it. Plus,
I like replying to you.

In the context of the OP - what do you use - malloc or new ? Your less
likely to get into trouble using new if you don't know about malloc(0)
having two conforming behaviours. 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 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. 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.
Ah, but your point, as I read it, was that malloc's behaviour when
passed 0 as an argument was somehow less well-specified than its
behaviour in the face of other inputs.

malloc(0) just leads to novices creating code that may or may not be
portable. That's the only thing I was alluding to.
... This is, as supported by
careful examination of the C standard, not true.

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.
... Code which relies on
malloc returning a non-NULL pointer, and code which relies on new
returning a pointer rather than throwing an exception, *must* be
prepared for the alternative as it will eventually happen in all but
the most trivial examples. Period.

Never argued any different. However demanding it and getting it are two
very different things.
Neither the C nor the C++ standard guarantees that conforming code
will behave identically on all platforms. They guarantee that
conforming code will behave *predictably* on all conforming
platforms. This is true of all programming languages that have formal
definitions.

There is a certain level of expectation that calling "malloc(1)" at the
beinnging of main will return non zero. I have found numerous
applications that segv when it does not (when I was doing my malloc
testing). Even libc on many platforms died even before main() was
called when I did my tests 15 or so years ago. I suspect things are a
little better now.
Cite from the relevant standards? I don't see any evidence that
that's actually true.

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.
and hence it will result in better code portability.

*If* 'new' has a more strict definition than malloc, then code that
utilises 'new' will have a more strictly-defined behaviour than code
that uses malloc, yes.
Yes.
Again, so what ? The point is that code (bad or otherwise) exists such
that it works on one platform and not another because of THIS behaviour
of malloc which does not happen with new. That's all. If you think it
does not exist, see my code above. If you don't believe that anyone
would write code like that, get more experience.

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:

--example1.cpp--

class Empty {
};

int main () {
Empty *e = new Empty (); // Here

delete e;
}

Conforming or not, it would be a terribly useless compiler if it did
throw bad_alloc here. Hence I think none do unless memory really can't
be allocated as in it is exhasted by some implementation defined meaning
of exhausted.

Besides sizeof Empty is probably 1 on most implementations so it's not
relevant to this discussion when comparing it to malloc(0). The
standard requires that each object have a unique address. There is a
trivial base class optimization that does essentially make Empty zero
sized when derived from but compilers are free to simply sizeof Empty 1.
--example2.cpp--

int main () {
int *i = new int[0]; // Here

delete i;
}

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).
--end--

Once again, such an implementation would be conforming: the behaviour
of both programs is predictable. It would merely be extremely poor.

.... and pointless.

Do you know of the existance of a platform that will consistantly throw
bad_alloc for "int *i = new int[0];" ?

....
I find it hard to believe you expect the ISO standards committee to
control the behaviour of myriad implementation vendors, as that's what
enforcing any specific behaviour from a memory-allocation function
would require.

What are standards for again ?
... It would also require absolute cooperation from OS
vendors and hardware manufacturers.

That's one of the side effects of standards.
While I'm not psychic, I believe the C committee's goals to include
defining a language in which both extremely portable code and
extremely platform-dependant code may be written.

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.
... Consequently, the
standard defines rules within which code is guaranteed to behave
predictably under any conforming implementation; it is up to
programmers to be familiar with these rules if they wish to write code
that's as portable as C allows.

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.
... The language does not demand that all
code remain within these rules.

What do you think we're discussing ?
 
G

Gianni Mariani

Old Wolf wrote:
....
It seems you are criticizing malloc based on
a buggy code-snippet you wrote. I am saying
that it is not malloc being non-portable, it
is that your code has a bug.

my code ?

You really don't see the point ?
 
I

Ian Collins

Gianni said:
Old Wolf wrote:
....

my code ?

You really don't see the point ?

The point is that no one appears to see your points. Maybe that should
tell you something.
 
O

Owen Jacobson

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:
....
--example2.cpp--

int main () {
int *i = new int[0]; // Here
delete i;
}

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.
... and pointless.

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.
 
G

Gianni Mariani

I would never have imagined that malloc(0) could have generated so much
discussion. Let's get back to the OP question.

Do we agree this is an appropriate answer ?

I and at least one other is insane for perpetuating this dribble.

The OP wants to know if malloc is acceptable in C++ code - Yes it is.

Should one prefer new over malloc - answer - depends. new is
significantly better for most uses and *seems* to provide more
consistant behaviour than malloc(0) (edge case).

If "realloc()" behaviour is needed for very large blocks of memory, then
malloc() is the only standard choice that provides potentially
significant performance improvements.

As for the rest of your post. If you really really really care, I'll
respond but it's getting beyond silly.
 
G

Gianni Mariani

Ian said:
The point is that no one appears to see your points. Maybe that should
tell you something.

The point is this: malloc(0) on some platforms always returns null while
on others it returns a 0 sized block of memory (essentially no different
than if you had called malloc(1)).

Hence someone who writes code like the example I posted, is potentially
going to run into trouble with platforms that return null on malloc(0)
and hence it's a portability issue.

If this is all fixed now and all modern versions of malloc behave in the
same way - then we're all good, however this was a problem 15 years ago.
 
G

Gianni Mariani

Old said:
The point is that new has a more strict definition and hence it
will result in better code portability. It seems damn obvious to me,
why cant you see it.

Nobody else can see it either .. perhaps it's you that's wrong?

Firstly, new does not have a more strict definition.
malloc(0) has two options:
- return NULL
- return valid pointer

new T[0] has three options:
- throw exception
- return valid pointer
- return NULL, if T has a custom allocator (see 5.3.4/13)

So it seems to me that 'new' is LESS strictly specified than malloc.

I can provide my own malloc library as well that sings dixie (and there
are plenty of malloc alternatives). It seems your statement is
unsupportable.
Secondly, strict definition doesn't mean more portable.
In fact, C and C++ specifications were deliberately
made as non-strict as possible, to _improve_ portability.

Portablility of what ? If the standard says that malloc(0) behaves
predominantlty like malloc(1) (which it appears it does not), then the
unfortunate case is that code will be written that will not work on all
platforms.
It's no coincidence that C is available on almost every
single platform that has anything other than assembly.

Do you infer here that the portability (or implementability) of the
compiler is somehow related to portability of application code ? I'll
let you make your own conclusion as to how relevant that statement may be.
 
O

Old Wolf

Old said:
Firstly, new does not have a more strict definition.
malloc(0) has two options:
- return NULL
- return valid pointer
new T[0] has three options:
- throw exception
- return valid pointer
- return NULL, if T has a custom allocator (see 5.3.4/13)
So it seems to me that 'new' is LESS strictly specified than malloc.

I can provide my own malloc library as well that sings dixie (and there
are plenty of malloc alternatives). It seems your statement is
unsupportable.

ISO/IEC 9899:1999 7.20.3.3
[#3] The malloc function returns either a null
pointer or a pointer to the allocated space.

(The text for ISO/IEC 9899:1990, which C++ refers to,
is similar but I do not have an exact copy of it).
Portablility of what ? If the standard says that malloc(0)
behaves predominantlty like malloc(1) (which it appears it
does not), then the unfortunate case is that code will be
written that will not work on all platforms.

Then that code is non-portable, and the fault lies with
the programmer. I don't see why you treat this any
differently than code like:

try { char *ptr = new x[1000000]; }
catch(...) { explode_nuclear_weapon(); }

Works fine on my platform but someone else might have a
problem with it -- do we blame C++ for allowing the
programmer to write code that will not work on all platforms?
Do you infer here that the portability (or implementability) of the
compiler is somehow related to portability of application code ?

Yes (BTW, I imply, you infer). How portable is an
application that only runs on one platform? (for
example, a Visual Basic program).
 
G

Gianni Mariani

Old Wolf wrote:
....
Then that code is non-portable, and the fault lies with
the programmer. I don't see why you treat this any
differently than code like:

try { char *ptr = new x[1000000]; }
catch(...) { explode_nuclear_weapon(); }


Let's establish the first point.

Will the code I posted earlier in this thread work as expected on all
platforms with a conforming malloc implementation ?
 
O

Old Wolf

Let's establish the first point.

Will the code I posted earlier in this thread work as expected on all
platforms with a conforming malloc implementation ?

I assume you are referring to the following code:
struct mystring
{
mystring( int len )
: len( len ),
ptr( malloc( len )
{
if ( ! ptr )
throw bad_alloc;
}
};

I expect the above code will throw bad_alloc
on some conforming implementations, and not
throw on other conforming implementations.

So, will it work as expected? I say yes, without
actually running the code to see.
 
J

James Kanze

Different behaviour on different systems. If I write code that assumes
malloc(0) returns unique values and it returns 0 on some, it will break.
I'm not sure if that's the only one but it is a source of inconsistency
between platforms.

And how is this different from new? If you allocate an array of
length 0 with new, it may fail, or it may return a unique
pointer, which can be copied and tested, but not deallocated.
Just like malloc.
 
J

James Kanze

What about that exception on one platform and not another for mystring(0) ?

And how do you propose to avoid it? The operator new function
has exactly the same variance.
It's a really simple concept here, why don't you get it ? Different
"standard" behaviour on different platforms leads to less portable code
which is the statement Torsten made which is now obvious.

Yes, but this difference is present in both malloc and operator
new.
Sure *I* can write code that works correctly on all platforms, so what ?
The read question is, can there exist conforming code that works on
one platform and not another. That is obviously true (by existence).

That's obviously true, even without any variation in the
specification.
What ? malloc(23) should only return null in the case of a bug (non
conformance) or inability to allocate memory (bad_alloc). Are you
advocating otherwise ?

The standard makes no real guarantees. It's also possible that
the first call to a function from main will cause stack
overflow.

As far as the standard is concerned, the C standard allows
malloc(0) to return null, even when malloc(1) would succeed, and
the C++ standard allows new char[0] (or operator new(0)) to
throw bad_alloc, even when new char[1] (or operator new(1))
would succeed. As a quality of implementation issue, of course,
both behaviors would be considered unacceptable, but the
standard offers no guarantee; it's purely a quality of
implementation issue. (Technically, the C standard requires an
implementation to document whether malloc(0) will systematically
fail, or only sometimes; the C++ standard leaves it somewhat
more open, and doesn't require any documentation. In practice,
there's no difference.)
 
J

James Kanze

Owen Jacobson wrote:

[...]
Again this is relevant to this discussion how ? The "mystring" code I
hacked earlier is an example where on one platform malloc(0) returning
different values on different platforms causing vastly different things
to happen being a portability issue. That's all. Code like this
exists. The point is that new has a more strict definition and hence it
will result in better code portability. It seems damn obvious to me,
why cant you see it.

Because it's not true. You keep claiming that operator new has
a stricter specification, but the actual standard disagrees with
you: "[concerning the allocation functions...]Even if the size
of the space requested is zero, the request can fail. If the
request succeeds, the value returned shall be a non-null pointer
value (4.10) p0 different from any previously returned value p1,
unless that value p1 was subsequently passed to an operator
delete. The effect of dereferencing a pointer returned as a
request for zero size is undefined."

The only difference I can see between this and the C standard's
requirements for malloc is that in C, whether malloc(0) will
always fail, or will only fail when malloc of some greater
amount will fail, is formally implementation defined, which
means the choice must be documented by the implementation. In
practice, however, 1) implementations don't document it, or at
least, they hide such documentation so well that I've never been
able to find it, and 2) an implementation can document that the
behavior is the same "as if the size were some nonzero
value[...]", and then use some ridiculously large value for that
nonzero value. In practice, both in C and in C++, we count on
the quality of the implementation. And expect that the C++
global allocator function :):eek:perator new(size_t)) and malloc
behave in the same fashion.
Again, so what ? The point is that code (bad or otherwise) exists such
that it works on one platform and not another because of THIS behaviour
of malloc which does not happen with new.

Except that it does. Just as often.
That's all. If you think it
does not exist, see my code above. If you don't believe that anyone
would write code like that, get more experience.
Very nice. Rather a stupid thing to put in the standard IMHO.

Apparently, the authors of the C++ standard didn't agree,
because they created new wording to say the same thing (except
that since it isn't "implementation defined", the implementation
is not required to document its choice).
 
G

Gianni Mariani

Are you in NZ? I had a vague impression you were in Germany.
I assume you are referring to the following code:

Yes, it is.
I expect the above code will throw bad_alloc
on some conforming implementations, and not
throw on other conforming implementations.

If the same thing can be said about "new char[len]" then I'm wrong
otherwise this is the only point I am making.

It's subtle, it's incorrect code, its bad with all the arguments you'd
like to make, however, it's true that such code is written and running
today.
 
G

Gianni Mariani

James Kanze wrote:
....
And how is this different from new? If you allocate an array of
length 0 with new, it may fail, or it may return a unique
pointer, which can be copied and tested, but not deallocated.
Just like malloc.

Look at my last post to Mr Wolf. Let's join threads.
 
J

James Kanze

On Jun 7, 8:09 pm, Gianni Mariani <[email protected]> wrote:
That's what "implementation defined" means, yes. The entire behaviour
of malloc is, somewhat obliquely, implementation-defined. The only
properties malloc must have in a conforming implementation is always
producing any of a fixed set of outputs for any given input, and that
subsequent operations on those values also have predictable results.

I wouldn't even say that a fixed set of outputs is required.
All that it required is that IF it returns a non-null pointer,
the user must be able to read and write the n bytes starting at
that address. The same as with operator new(). The
requirements are exactly the same.

I wonder if it's worth noting that some widespread
implementations don't always meet these requirements, be it
malloc or operator new. And others meet them in rather strange
ways: I've encountered cases where malloc/operator new() simply
suspended the process until more memory was available---fully
conforming, since the standard doesn't say how long
malloc/operator new might take:).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,888
Messages
2,569,964
Members
46,294
Latest member
HollieYork

Latest Threads

Top