Topic: Standard definition of nothrow new calls call normal new, or not?
Author: James.Kanze@dresdner-bank.com
Date: 1999/07/13 Raw View
In article <7m35eb$ntr$1@nnrp1.deja.com>,
wicklund@netcom.com wrote:
> In article <199907071938.OAA28189@ares.flash.net>,
> blargg@flash.net wrote:
> > On some compilers I use, the standard definition of operator new (
size_t,
> > nothrow_t ) does *not* call operator new ( size_t ), but instead
uses the
> > same internal algorithm that operator new ( size_t ) uses. This is
all
> > fine unless the user overrides operator new ( size_t ), but not
operator
> > new ( size_t, nothrow_t ). In that case, undefined behavior occurs
when
> > code allocates with nothrow new, then deletes normally. Is it
required
> > that the standard definition of the nothrow new call the non-nothrow
> > version? As in:
> > void* std::operator new ( std::size_t s, std::nothrow_t const& )
throw () {
> > try {
> > return ::operator new ( s );
> > } catch ( std::bad_alloc& ) {
> > // fall-through
> > }
> > return NULL;
> > }
> There are environments (especially embedded or "kernel" type code)
which
> cannot tolerate exceptions. As another response stated, implementing
> the other way around (exception throwing "new" via nothrow "new")
makes
> more sense in many ways.
> This is one of those problems with C++ and other OO languages. Having
a
> lot of options means repeating a lot of code. You can make a similar
> argument about operator new vs operator new[]. If I remember
correctly
> they can be independently replaced, though the replacement for each
may
> use the same algorithm.
There is a difference, however, with regards to the nothrow version.
The system operator new[]() is guaranteed to obtain memory by calling
operator new(), so (ignoring nothrow for the moment) if you replace
operator new (say for debugging purposes), you still intercept all of
the allocations. There is no such guarantee for the nothrow new, so if
you want to intercept all dynamic allocations, you need to replace both
new's. (The nothrow version of operator new[]() is guaranteed to call
the nothrow version of operator new(), so you don't need to replace that
one as well.)
--
James Kanze mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49 (069) 63 19 86
27
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Salters <msalters@lucent.com>
Date: 1999/07/08 Raw View
blargg@flash.net wrote:
> On some compilers I use, the standard definition of operator new ( size_t,
> nothrow_t ) does *not* call operator new ( size_t ), but instead uses the
> same internal algorithm that operator new ( size_t ) uses. This is all
> fine unless the user overrides operator new ( size_t ), but not operator
> new ( size_t, nothrow_t ). In that case, undefined behavior occurs when
> code allocates with nothrow new, then deletes normally. Is it required
> that the standard definition of the nothrow new call the non-nothrow
> version? As in:
> void* std::operator new ( std::size_t s, std::nothrow_t const& ) throw () {
> try {
> return ::operator new ( s );
> } catch ( std::bad_alloc& ) {
> // fall-through
> }
> return NULL;
> }
I don't know whether that is required, but I can make a pretty good guess.
Since it is as easy to write the throwing new in terms on the non-throwing:
void* std::operator new( std::size_t s) throw (std::bad_alloc) {
void *p = ::operator new (s,std::nothrow);
if (!p) throw std::bad_alloc;
return p;
}
and operator new(nothrow) can be implemented alongside with malloc, I
do not think is is wise to require either behavior.
> I find it surprising that the default nothrow wouldn't call the normal
> one, as I thought the purpose of the nothrow form was not for performance
> reasons, but for protocol reasons (returning NULL from a new expression
> instead of throwing an exception).
Well, I'd say my example suggests a good reason why things would be
otherwise. But I agree that the new vs. new (nothrow) conflicts are
something I'm not happy with. I understand the rationale for either,
I'm just not happy with the standard allowing both.
Michiel Salters
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/07/08 Raw View
blargg@flash.net wrote in message <199907071938.OAA28189@ares.flash.net>...
>
>On some compilers I use, the standard definition of operator new ( size_t,
>nothrow_t ) does *not* call operator new ( size_t ), but instead uses the
>same internal algorithm that operator new ( size_t ) uses. Is it required
>that the standard definition of the nothrow new call the non-nothrow
>version?
No. 17.4.3.4 "Replacement Functions" allows eight functions (new/delete x
nothrow/throw x array/normal) to be replaced.
For the reasons you specify, it is a good idea to replace both the
throw/nothrow versions at the same time. For similar reasons it is a good
idea to replace both new/delete versions at the same time.
I don't believe it is necessary to replace both array/normal functions at
the same time, but I would be leary of implementing the array function in
terms of the non-array function, or vice-versa.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/07/09 Raw View
On 7 Jul 1999 20:07:57 GMT, blargg@flash.net wrote:
: On some compilers I use, the standard definition of operator new ( size_t,
: nothrow_t ) does *not* call operator new ( size_t ), but instead uses the
: same internal algorithm that operator new ( size_t ) uses.
18.4.1.1 states that the nothrow version allocates memory _as if_ from
the normal version.
: This is all
: fine unless the user overrides operator new ( size_t ), but not operator
: new ( size_t, nothrow_t ).
#include <new>
struct S {
void* operator new (std::size_t) throw (std::bad_alloc);
};
void f () {
S* p1 = new S;
S* p2 = new (std::nothrow) S;
}
The second new expression is an error because S::operator new hides all
operator new functions.
: In that case, undefined behavior occurs when
: code allocates with nothrow new, then deletes normally.
It would take some work to do that. Sounds like Machiavelli not
Murphy to me.
: Is it required
: that the standard definition of the nothrow new call the non-nothrow
: version?
See above. Is there an _as if_ violation?
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: wicklund@netcom.com
Date: 1999/07/09 Raw View
In article <199907071938.OAA28189@ares.flash.net>,
blargg@flash.net wrote:
>
> On some compilers I use, the standard definition of operator new (
size_t,
> nothrow_t ) does *not* call operator new ( size_t ), but instead uses
the
> same internal algorithm that operator new ( size_t ) uses. This is all
> fine unless the user overrides operator new ( size_t ), but not
operator
> new ( size_t, nothrow_t ). In that case, undefined behavior occurs
when
> code allocates with nothrow new, then deletes normally. Is it required
> that the standard definition of the nothrow new call the non-nothrow
> version? As in:
>
> void* std::operator new ( std::size_t s, std::nothrow_t const& )
throw () {
> try {
> return ::operator new ( s );
> } catch ( std::bad_alloc& ) {
> // fall-through
> }
> return NULL;
> }
There are environments (especially embedded or "kernel" type code) which
cannot tolerate exceptions. As another response stated, implementing
the other way around (exception throwing "new" via nothrow "new") makes
more sense in many ways.
This is one of those problems with C++ and other OO languages. Having a
lot of options means repeating a lot of code. You can make a similar
argument about operator new vs operator new[]. If I remember correctly
they can be independently replaced, though the replacement for each may
use the same algorithm.
When you start inheriting code this also shows up -- you need to rewrite
the same 2-3 constructors for each subclass and often need to rewrite
things like comparisons in a very mechanical manner. A way to avoid
this repetition would be nice, but I see it in all OO languages I can
think of at the moment (C++, Eiffel, Sather, etc).
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: blargg@flash.net
Date: 1999/07/07 Raw View
On some compilers I use, the standard definition of operator new ( size_t,
nothrow_t ) does *not* call operator new ( size_t ), but instead uses the
same internal algorithm that operator new ( size_t ) uses. This is all
fine unless the user overrides operator new ( size_t ), but not operator
new ( size_t, nothrow_t ). In that case, undefined behavior occurs when
code allocates with nothrow new, then deletes normally. Is it required
that the standard definition of the nothrow new call the non-nothrow
version? As in:
void* std::operator new ( std::size_t s, std::nothrow_t const& ) throw () {
try {
return ::operator new ( s );
} catch ( std::bad_alloc& ) {
// fall-through
}
return NULL;
}
I find it surprising that the default nothrow wouldn't call the normal
one, as I thought the purpose of the nothrow form was not for performance
reasons, but for protocol reasons (returning NULL from a new expression
instead of throwing an exception).
I have also realized this applies to the placement delete form of nothrow,
used when an exception occurs after allocation with nothrow new, during
construction of the object(s). This would need to call through to normal
operator delete too.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]