Re: Using malloc in C++?
On Jun 7, 8:09 pm, Gianni Mariani <gi3nos...@mariani.ws> wrote:
Owen Jacobson wrote:
... Or any of
a number of other circumstances?
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.
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 C standard, from whence malloc comes, is extremely conservative
when it comes to defining what standard library functions that have
side effects are required to do. The verbiage in C99 is as follows:
If the space cannot be allocated, a null pointer is
returned.
It does not say "If the space is unavailable", or "If memory is full",
or anything else, merely "if the space cannot be allocated."
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.
... As I
said: it's a quality of implementation issue; a sufficiently poor
implementation may never be able to allocate exactly 23 bytes and
unwilling to allocate more than requested.
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.
... Such an implementation
would be conformant, even though it would likely have no users.
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.
Isn't it time to get these implementations fixed, Gianni?
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--