469,327 Members | 1,200 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,327 developers. It's quick & easy.

Using malloc in C++?

I have read in Bjarne Stroustrup that using malloc and free should be
avoided in C++ because they deal with uninitialized memory and one
should instead use new and delete.

But why is that a problem? I cannot see why using malloc instead of new
does not give the same result.
Jun 7 '07
71 18352
Old Wolf wrote:
On Jun 8, 3:09 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
>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.
Jun 8 '07 #51
On Jun 9, 9:41 am, Gianni Mariani <gi3nos...@mariani.wswrote:
Old Wolf wrote:
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).
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.
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?
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 ?
Yes (BTW, I imply, you infer). How portable is an
application that only runs on one platform? (for
example, a Visual Basic program).


Jun 10 '07 #52
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 ?
Jun 11 '07 #53
On Jun 11, 11:57 am, Gianni Mariani <gi3nos...@mariani.wswrote:
Old Wolf wrote:
Then that code is non-portable, and the fault lies with
the programmer.

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.

Jun 11 '07 #54
On Jun 7, 1:37 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Ian Collins wrote:
Gianni Mariani wrote:
Ian Collins wrote:
....
malloc(0)
Specified as far as you will either get a pointer to a block of >0 bytes
or NULL, just like any other size.
That would be a problem then.
Why? What ever you get from malloc, you can pass to free.
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.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 11 '07 #55
On Jun 8, 2:23 am, Gianni Mariani <gi3nos...@mariani.wswrote:
Owen Jacobson wrote:
On Jun 7, 3:41 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
...
struct mystring
{
mystring( int len )
: len( len ),
ptr( malloc( len )
{
if ( ! ptr )
{
throw bad_alloc;
}
}
......
};
Allowing for typos (you're missing the closing ) on the initialisation
of ptr), I don't see anything about that code that's broken by
malloc(0) returning NULL.
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.
... The constructor as written validates the
assumption that a block of memory representing the string is available
and fails construction if not. That's a perfectly reasonable
assumption for the ensuing, elided code to make.
Keep in mind that, as written, malloc(23) is allowed to always return
NULL too -- it's a quality of implementation issue that it doesn't,
not a conformance issue. On such a system, mystring(23) would always
fail because the assumption it validates is not satisfied by that
system.
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.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 11 '07 #56
On Jun 8, 5:09 am, Gianni Mariani <gi3nos...@mariani.wswrote:
Owen Jacobson wrote:
[...]
... 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. 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 (::operator new(size_t)) and malloc
behave in the same fashion.
... 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.
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.
The standard does continue on to describe what appears to be a special
case for malloc(0):
If the size of the space requested is zero, the behavior
is implementation- defined: either a null pointer is
returned, or the behavior is as if the size were some
nonzero value, except that the returned pointer shall not
be used to access an object.
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).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 11 '07 #57
Old Wolf wrote:
On Jun 11, 11:57 am, Gianni Mariani <gi3nos...@mariani.wswrote:
>Old Wolf wrote:
Are you in NZ? I had a vague impression you were in Germany.
>>
>>Then that code is non-portable, and the fault lies with
the programmer.
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:
Yes, it is.
>
>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.
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.
Jun 11 '07 #58
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.
Jun 11 '07 #59
On Jun 8, 5:59 am, Owen Jacobson <angrybald...@gmail.comwrote:
On Jun 7, 8:09 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
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:-).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 11 '07 #60
James Kanze wrote:
... In practice,
there's no difference.)
.... no difference in the standard ? Or implementations ?

I have yet to encounter a C++ impl that systematically throws bad_alloc
on new char[0]. I can't say the same for malloc(0), although I have not
looked lately.


Jun 11 '07 #61
On Jun 11, 2:25 am, James Kanze <james.ka...@gmail.comwrote:
On Jun 8, 5:59 am, Owen Jacobson <angrybald...@gmail.comwrote:
On Jun 7, 8:09 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
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.
Well, since there are a finite number of potentially-valid values for
any given pointer type, I think that (much more comfortable)
definition is equivalent. :)
I wonder if it's worth noting that some widespread
implementations don't always meet these requirements, be it
malloc or operator new.
Probably. MS Visual C++ 6, as I recall, returns NULL from failed
'new' expressions rather than throwing. Then again, it was released
before the C++ standard.
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:-).
Come to think of it, does the C++ standard constrain execution time
anywhere? I can imagine an implementation of int operator+ (int m,
int n) with O(nm*nm) complexity with large constant factors; would it
be conforming? What about the behaviour of the C++ standard library?

OT: Is google groups getting signatures wrong, or are you, James? The
sig separator should be "-- \n"; if that's what you're sending, then
google groups is no longer stripping signatures from replies.

Jun 11 '07 #62
On Jun 11, 12:38 pm, Owen Jacobson <angrybald...@gmail.comwrote:
On Jun 11, 2:25 am, James Kanze <james.ka...@gmail.comwrote:
On Jun 8, 5:59 am, Owen Jacobson <angrybald...@gmail.comwrote:
On Jun 7, 8:09 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
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.
Well, since there are a finite number of potentially-valid values for
any given pointer type, I think that (much more comfortable)
definition is equivalent. :)
I wonder if it's worth noting that some widespread
implementations don't always meet these requirements, be it
malloc or operator new.
Probably. MS Visual C++ 6, as I recall, returns NULL from failed
'new' expressions rather than throwing. Then again, it was released
before the C++ standard.
Yes. Still, I remember the one time I tested it (some eight or
nine years ago, under Windows NT), it just suspended the
process; it was impossible to get either a null pointer or an
exception. That could have depended on the configuration of our
system, however; in the end, malloc/operator new must sometimes
get memory from the system, and if the system lies to them (e.g.
the default configuration of Linux) or suspends the process for
an indeterminate time, there's not much the library code can do
about it.
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:-).
Come to think of it, does the C++ standard constrain execution time
anywhere?
No. Usability and quality of implementation do, of course, but
not in any absolute terms.
I can imagine an implementation of int operator+ (int m,
int n) with O(nm*nm) complexity with large constant factors; would it
be conforming?
Of course. I've actually used machines where this was the case
for multiplication and divide.
What about the behaviour of the C++ standard library?
The only guarantees you get are complexity, expressed in the
number of certain primitive operations. Nothing about actual
time, nor the operations not being considered. (Thus, insert
into an std::list is "constant", measured in terms of calls to
the constructor. But it's perfectly conform to use an allocator
which is O(N^2), where N is the number of allocated blocks,
which would, of course, make the actual insertion times O(N^2).)
OT: Is google groups getting signatures wrong, or are you, James? The
sig separator should be "-- \n"; if that's what you're sending, then
google groups is no longer stripping signatures from replies.
I wish I knew. I've modified my environment so that I should be
sending the correct delimiter. At least, that's what, barring
false manipulation, ends up in the text buffer I'm editing (in
vim). Regretfully, a lot happens after that, and I'm having
problems finding out exactly what, much less doing anything
about it. Add to the fact that I post from several different
machines, with slightly different environments, and I don't
always know from which machine the posting which caused problems
comes from.

I've modified my signature on the machine here to indicate the
source; I'll do the same the next time I post from another
machine. If anyone sees a posting that is not conform, please
let me know, by email (no point in flooding the group), with all
of the headers of the posting in question, and I'll try and
trace it down. With no guarantee, however; I have no control
over what Google does. (On the other hand, I have sent error
messages to them before, and they've been acknowledged. I think
they do want to be conform, at least to some degree.)

I'm leaving my editor now. I've just confirmed that the
separator is "-- \n", with the space... And now I'm in the
post buffer of Firefox, and the space is still there.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 11 '07 #63
On Jun 11, 4:43 pm, James Kanze <james.ka...@gmail.comwrote:
On Jun 11, 12:38 pm, Owen Jacobson <angrybald...@gmail.comwrote:
[...]
OT: Is google groups getting signatures wrong, or are you, James? The
sig separator should be "-- \n"; if that's what you're sending, then
google groups is no longer stripping signatures from replies.
I wish I knew. I've modified my environment so that I should be
sending the correct delimiter. At least, that's what, barring
false manipulation, ends up in the text buffer I'm editing (in
vim). Regretfully, a lot happens after that, and I'm having
problems finding out exactly what, much less doing anything
about it. Add to the fact that I post from several different
machines, with slightly different environments, and I don't
always know from which machine the posting which caused problems
comes from.
I've modified my signature on the machine here to indicate the
source; I'll do the same the next time I post from another
machine. If anyone sees a posting that is not conform, please
let me know, by email (no point in flooding the group), with all
of the headers of the posting in question, and I'll try and
trace it down. With no guarantee, however; I have no control
over what Google does. (On the other hand, I have sent error
messages to them before, and they've been acknowledged. I think
they do want to be conform, at least to some degree.)
I'm leaving my editor now. I've just confirmed that the
separator is "-- \n", with the space... And now I'm in the
post buffer of Firefox, and the space is still there.
OK. The message showed up here for display with the space still
their. I hit the answer button, and 1) the signature was
present in the post box, and 2) the trailing space wasn't there.
So the problem seems to be with Google's posting mechanism (but
it could be that Google just doesn't strip signatures, and
Firefox strips the trailing blank). I'll edit my .sig to
suppress the accented characters, try again, and then get back
to Google with a bug report. (I should also try the same thing
from some other configurations. I've noticed that the headers
aren't the same on the machine I post from on week-ends as they
are here.)

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientee objet/
Beratung in objektorientierter Datenverarbeitung
9 place Semard, 78210 St.-Cyr-l'Ecole, France, +33 (0)1 30 23 00 34

Jun 11 '07 #64
On Jun 11, 12:02 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
James Kanze wrote:
... In practice,
there's no difference.)
... no difference in the standard ? Or implementations ?
I have yet to encounter a C++ impl that systematically throws bad_alloc
on new char[0]. I can't say the same for malloc(0), although I have not
looked lately.
I've yet to encounter an implementation of operator new which
did anything other than just call malloc, and throw bad_alloc if
it returned null.

Many, many years ago, before the C standard, it wasn't really
clear what malloc(0) should do, and implementations did vary
greatly. The C standards committee set the rules in 1988, and
in practice, I've never had any problems with malloc(0) with a
compiler which claimed to be ANSI or ISO C; they all seem to
return non-null pointers when they can. Obviously, I've not
tried all of the C/C++ compilers out there, but my impression is
that this is a problem that has disappeared.

(Of course, I can understand your hesitancy if you've actually
been burned by it. Even a long time ago. I tend to not forget
my wounds either.)

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 11 '07 #65
On Jun 7, 1:46 am, Ian Collins <ian-n...@hotmail.comwrote:
desktop wrote:
For a bucket of bytes or a C style struct, using malloc/free or
new/delete makes little or no difference. For objects with constructors
and/or destructors you have to use new/delete, so you may as well use
the same for all allocations.

it makes a difference even for POD as new throws when it fails and
malloc does not.
So for malloc you need to test for success. For new you don't.

Jun 11 '07 #66
Peter wrote:
On Jun 7, 1:46 am, Ian Collins <ian-n...@hotmail.comwrote:
>desktop wrote:
For a bucket of bytes or a C style struct, using malloc/free or
new/delete makes little or no difference. For objects with constructors
and/or destructors you have to use new/delete, so you may as well use
the same for all allocations.


it makes a difference even for POD as new throws when it fails and
malloc does not.
So for malloc you need to test for success. For new you don't.
How do you handle the exception ?
Jun 11 '07 #67
On Jun 11, 9:23 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Are you in NZ?
Yes
Jun 12 '07 #68
On Jun 11, 3:46 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Peter wrote:
On Jun 7, 1:46 am, Ian Collins <ian-n...@hotmail.comwrote:
desktop wrote:
For a bucket of bytes or a C style struct, using malloc/free or
new/delete makes little or no difference. For objects with constructors
and/or destructors you have to use new/delete, so you may as well use
the same for all allocations.
it makes a difference even for POD as new throws when it fails and
malloc does not.
So for malloc you need to test for success. For new you don't.

How do you handle the exception ?

The point with exception handling is that you don't need to do
anything at the point where the exception is thrown -- means at the
point you call operator new.
You can deal with the exception in some function down the stack --
usually in main() or in the message function for GUI-applications.
In well designed code try-catch blocks are rare.

Jun 12 '07 #69
On Jun 11, 3:46 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Peter wrote:
On Jun 7, 1:46 am, Ian Collins <ian-n...@hotmail.comwrote:
desktop wrote:
For a bucket of bytes or a C style struct, using malloc/free or
new/delete makes little or no difference. For objects with constructors
and/or destructors you have to use new/delete, so you may as well use
the same for all allocations.
it makes a difference even for POD as new throws when it fails and
malloc does not.
So for malloc you need to test for success. For new you don't.

How do you handle the exception ?

in well designed code try-catch blocks are rare.
Usually they reside in the main function or in the message function in
case of GUI application.
Thus you don't need to do anything in case of new fails,
as some function down the stack will deal with the exception.

Jun 12 '07 #70
Peter wrote:
On Jun 11, 3:46 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
>Peter wrote:
>>On Jun 7, 1:46 am, Ian Collins <ian-n...@hotmail.comwrote:
desktop wrote:
For a bucket of bytes or a C style struct, using malloc/free or
new/delete makes little or no difference. For objects with constructors
and/or destructors you have to use new/delete, so you may as well use
the same for all allocations.
it makes a difference even for POD as new throws when it fails and
malloc does not.
So for malloc you need to test for success. For new you don't.
How do you handle the exception ?


in well designed code try-catch blocks are rare.
Usually they reside in the main function or in the message function in
case of GUI application.
Thus you don't need to do anything in case of new fails,
as some function down the stack will deal with the exception.

The question is specific - "how do *you* handle the exception ?".

I think that most people think like you do - I don't need to worry about
it, someone else will handle it when in fact it's never tested and never
designed to be handled.

Not that I do any better mind you ... I make just as much a mess of it
as anyone else does.

The only point I am making is that it's very unlikely that expecting
some higher up frame to deal with my lower down frame's issue without at
least making the right design choices is going to work is a recipe for
failure.

Go ahead and try it. Set the process memory limit and run various
commands. Many of them crash and burn. I'd at least expect them to
complain very early about needing more memory to run.

One way I handled this in the past was to initially reserve a large
chunk o memory (1MB or somthing like that) and upon failure to get more
memory, I would set a flag and free the block and retry the memory
allocation. This would then set the application to alert the user that
they're out of memory and they should terminate other apps etc. If they
chose to proceed it would attempt to allocate it's memory reserve so it
could do it again. This was the only successful low memory handling
scheme I ever wrote. It can't be implemented using exceptions because
it needs to work before exceptions are thrown.
Jun 13 '07 #71
On Jun 13, 2:04 am, Gianni Mariani <gi3nos...@mariani.wswrote:
Peter wrote:
On Jun 11, 3:46 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Peter wrote:
On Jun 7, 1:46 am, Ian Collins <ian-n...@hotmail.comwrote:
desktop wrote:
For a bucket of bytes or a C style struct, using malloc/free or
new/delete makes little or no difference. For objects with constructors
and/or destructors you have to use new/delete, so you may as well use
the same for all allocations.
it makes a difference even for POD as new throws when it fails and
malloc does not.
So for malloc you need to test for success. For new you don't.
How do you handle the exception ?
in well designed code try-catch blocks are rare.
Usually they reside in the main function or in the message function in
case of GUI application.
Thus you don't need to do anything in case of new fails,
as some function down the stack will deal with the exception.
The question is specific - "how do *you* handle the exception ?".
Note that there are two very distinct levels involved. Even if
you don't want to handle the error locally, you still have to
ensure that your objects are in a coherent state when an
exception passes through. Something like:

int* p1 = new int[ 100 ] ;
int* p2 = new int[ 100 ] ;

is a memory leak, for example.

Luckily, if you're using operator new (but not malloc), this is
easy to test. Just replace the global operator new with one
which "runs out" on command. (This is a standard part of my
memory checking operator new.)
I think that most people think like you do - I don't need to
worry about it, someone else will handle it when in fact it's
never tested and never designed to be handled.
There's certainly no excuse for it never being tested. Just
insert an appropriate operator new, and write something like:

int allocCount = 0 ;
bool noMem = true ;
while ( noMem ) {
t.nextMinorCycle() ;
++ allocCount ;
noMem = false ;
Gabi::MemoryCheck memchk ;
memchk.setErrorTrigger( allocCount ) ;
try {
SetOfCharacter s( it.begin(), it.end() ) ;
} catch ( std::bad_alloc& ) {
noMem = true ;
}
memchk.resetErrorTrigger() ;
t.verify( memchk.unfreedCount(), 0 ) ;
}
Not that I do any better mind you ... I make just as much a mess of it
as anyone else does.
I know what you mean. I added the option to my MemoryCheck
class many years ago, but if you look at the code at my site,
none of the tests use it. I only started systematically testing
like this a couple of months ago. I might add that I found an
error the very first time I did such a test. And I consider
myself a fairly careful programmer.
The only point I am making is that it's very unlikely that
expecting some higher up frame to deal with my lower down
frame's issue without at least making the right design choices
is going to work is a recipe for failure.
Go ahead and try it. Set the process memory limit and run
various commands. Many of them crash and burn.
And those that don't crash and burn are likely to leak
resources, or end up in an inconsistent internal state.
I'd at least expect them to
complain very early about needing more memory to run.
One way I handled this in the past was to initially reserve a large
chunk o memory (1MB or somthing like that) and upon failure to get more
memory, I would set a flag and free the block and retry the memory
allocation. This would then set the application to alert the user that
they're out of memory and they should terminate other apps etc. If they
chose to proceed it would attempt to allocate it's memory reserve so it
could do it again. This was the only successful low memory handling
scheme I ever wrote. It can't be implemented using exceptions because
it needs to work before exceptions are thrown.
It's probably the best you can do in many cases. I work on
large scale servers. For the most part, they run on dedicated
machines, with what should be sufficient memory. If we run out
of memory, it's almost certainly because of a memory leak; we
free a pre-allocated block with hopefully enough memory to
ensure that logging will still work, log the problem, and abort
(which of course triggers a restart of the application). This
is done, of course, by means of the new_handler, and not by
catching exceptions.

There are exceptions. An LDAP server can receive arbitrarily
complex requests from the user, for example. Typically, it will
build such requests as a tree (with AND, OR and NOT nodes, as
well as predicates in leaf nodes). If one request fails because
of a lack of memory, it may simply be that it is too complex.
Catch bad_alloc, reject that request, and continue running. In
theory, at least; typically, the requests are parsed using
recursive descent, so where you run out of memory is when trying
to grow the stack:-). (There's no standard solution for that,
but I know how to handle it under Solaris.)

The fact that there can be such cases, of course, means that in
library code, you have to do the right thing, even if it doesn't
matter in most applications.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 13 '07 #72

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

10 posts views Thread by Christof Krueger | last post: by
17 posts views Thread by Johs32 | last post: by
2 posts views Thread by aziizvu | last post: by
8 posts views Thread by digz | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
reply views Thread by Purva khokhar | last post: by
reply views Thread by haryvincent176 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.