Topic: What Is `delete(void*, const nothrow_t&)' Good For?


Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/02/25
Raw View
Philip Koester wrote:
>
> The reason why there are two versions of new (one throwing bad_alloc, the
> other one taking a const nothrow_t reference, guaranteed to throw nothing)
> is plain to me:
>
>     // 1. Instantiate a new X, catch bad_alloc
>     try { X* p1 = new X; } catch (bad_alloc&) { cerr << "oops" << endl; }
>     // 2. Instantiate a new X, inquire operator new's return value
>     X* p2 = new(nothrow) X; if (!p2) cerr << "ummh" << endl;
>
> But why are there two complementary versions of operator delete?  Obviously,
> I can't say `delete(nothrow) p2;' -- anyway I don't see a reason to do so
> because the `ordinary' operator delete is declared to throw nothing as well.
> So, should I say:
>
>     X* p2 = new(nothrow) X;
>     ...
>     p2->~X(); // Call the dtor manually
>     operator delete(p2, nothrow); // Call the exact complement
>
> Just for the sake of symmetry?  What's the idea behind this?

If the constructor of X throws, C++ calls the operator delete
corresponding to the operator new. This is necessary to make
placement new work (think of what would happen if the memory
"allocated" with placement new would be deleted with normal
delete). OTOH, simply not deallocating for any placement-form
new would give ressource leaks for those placement form
operator new, which really allocate some memory, which must be
deallocated (possibly in a special way). new(nothrow) is
one of the placement new forms, and therefore the corresponding
delete is provided (which just calls - or even is an alias of -
normal operator delete). The special operator delete is not used
otherwise.
---
[ 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: Philip Koester <kozmik@okay.net>
Date: 1999/02/24
Raw View
The reason why there are two versions of new (one throwing bad_alloc, the
other one taking a const nothrow_t reference, guaranteed to throw nothing)
is plain to me:

    // 1. Instantiate a new X, catch bad_alloc
    try { X* p1 = new X; } catch (bad_alloc&) { cerr << "oops" << endl; }
    // 2. Instantiate a new X, inquire operator new's return value
    X* p2 = new(nothrow) X; if (!p2) cerr << "ummh" << endl;

But why are there two complementary versions of operator delete?  Obviously,
I can't say `delete(nothrow) p2;' -- anyway I don't see a reason to do so
because the `ordinary' operator delete is declared to throw nothing as well.
So, should I say:

    X* p2 = new(nothrow) X;
    ...
    p2->~X(); // Call the dtor manually
    operator delete(p2, nothrow); // Call the exact complement

Just for the sake of symmetry?  What's the idea behind this?

    Philip
---
[ 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: "Dave Abrahams" <abrahams@mediaone.net>
Date: 1999/02/24
Raw View
In article <7auu93$1v5l$1@news.ipf.de> , Philip Koester <kozmik@okay.net>
wrote:

> But why are there two complementary versions of operator delete?  Obviously,
> I can't say `delete(nothrow) p2;' -- anyway I don't see a reason to do so
> because the `ordinary' operator delete is declared to throw nothing as well.

Good question; it's to keep the the implementation from requiring any
special magic to handle exceptions thrown from constructors.  The language
standard says that if an object's constructor throws an exception when it is
allocated with a new-expression, the corresponding delete operator is
called. Of course, the regular operator delete would work just as well, but
since std::nothrow_t is just a regular type, a compiler writer would have to
write special case code to detect that. It's a lot cleaner to treat
std::nothrow the same as any other parameter to operator new.

A few more points:


    X* x = new (std::nothrow) X;
    delete x;

Since this code is legal, if you've replaced the default operator delete to
use a different allocator, you'd better also replace the no-throw version of
operator new to use the same allocator. Of course, since if X::X() throws an
exception the nothrow form of operator delete is called, you also have to
replace that. So the upshot is that if you replace any of the 4 global
operators new or delete, you have to replace all of them.

Finally, it should be obvious at this point that the nothrow version of
operator new isn't really useful anyway unless you're absolutely sure you're
constructing something whose constructor can't throw an exception.

-Dave



[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/24
Raw View
In article <7auu93$1v5l$1@news.ipf.de>, Philip Koester <kozmik@okay.net>
writes
>But why are there two complementary versions of operator delete?  Obviously,
>I can't say `delete(nothrow) p2;' -- anyway I don't see a reason to do so
>because the `ordinary' operator delete is declared to throw nothing as well.
>So, should I say:
>
>    X* p2 = new(nothrow) X;
>    ...
>    p2->~X(); // Call the dtor manually
>    operator delete(p2, nothrow); // Call the exact complement
>
>Just for the sake of symmetry?  What's the idea behind this?

When an attempt to instantiate an object involving dynamic resources
fails we have a problem with recovery.  For example, suppose you are
using a simple placement new to locate the object in a place of your
choice, you do not want a plain delete to be used in rolling back
because that would attempt to free memory which was not acquired as part
of the construction process.  To solve this problem C++ allows provision
of special operator delete overloads for the compiler's use.

Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ 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: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/02/24
Raw View
Philip Koester <kozmik@okay.net> writes:

>The reason why there are two versions of new (one throwing bad_alloc, the
>other one taking a const nothrow_t reference, guaranteed to throw nothing)
>is plain to me:
...
>But why are there two complementary versions of operator delete?

So that the memory will be deallocated if you can `new (no_throw) Foo'
and Foo's constructor throws an exception.  See section 5.3.4 [expr.new]
paragraphs 17-19.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh>  |   but source code lives forever"
PGP: finger fjh@128.250.37.3        |     -- leaked Microsoft memo.


[ 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: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1999/02/24
Raw View
On Feb 23, 1999, Philip Koester <kozmik@okay.net> wrote:

> The reason why there are two versions of new [snip] is plain to me:

>     try { X* p1 = new X; } catch (bad_alloc&) { cerr << "oops" << endl; }

>     X* p2 = new(nothrow) X; if (!p2) cerr << "ummh" << endl;

> But why are there two complementary versions of operator delete?

Because if the constructor of the object throws an exception, it is
the operator delete symmetric to the operator new that will be called
to free the memory allocated by operator new.

So, if X() throws in the first case, `operator delete(void*)' will be
called; in the second case, it will be `operator delete(void*,
nothrow_t const&)'

--
Alexandre Oliva  http://www.dcc.unicamp.br/~oliva  aoliva@{acm.org}
oliva@{dcc.unicamp.br,gnu.org,egcs.cygnus.com,samba.org}
Universidade Estadual de Campinas, SP, Brasil


[ 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              ]