Topic: STL allocators that don't throw bad_alloc


Author: "James Russell Kuyper Jr." <kuyper@wizard.net>
Date: Thu, 16 Aug 2001 20:12:40 GMT
Raw View
Attila Feher wrote:
>
> "James Russell Kuyper Jr." wrote:
> >
> > Howard Taitel wrote:
> > >
> > > Is it legal to write an allocator that throws something other than
> > > bad_alloc upon failure?  In other words, does the STL code ever
> > > explicitly try to catch bad_alloc?
> >
> > In section 20.1.5, Table 32 only specifies that allocate() may throw "an
> > appropriate exception". It doesn't specify what that exception would be.
> > All of the standard-defined containers are required to accept and work
> > properly with any user-provided allocator that meets the requirements
> > listed in 20.1.5.
> >
> > Therefore, a standard-defined container may only catch bad_alloc if
> > doing so doesn't make it violate the standard's requirements for that
> > container if the allocator decides to throw something else instead.
> >
> > I won't bother trying to figure out the all of the implications of that
> > fact, but there certainly are some. For instance, if any exception
> > thrown during an insert() of a single object into a sequence container,

Note: I misread which section that requirement is in; it's in 23.1, not
23.1.1, and therefore applies to all containers, not just sequences.

> > then insert() is required to have no effect. Therefore, if insert()
> > makes any changes to the container before calling allocate(), it has to
> > catch all possible exceptions thrown by allocate(), and in the exception
> > handler undo whatever it changes it made. It can't make do by catching
> > only bad_alloc. It can't even make do by catching std::exception&, since
> > there's no requirement that the relevant exception is derived from
> > std::exception.
> [SNIP]
>
> What about inheriting this "myOwnBadAlloc" from bad_alloc?  In this case
> the STL which looks out for bad alloc can catch it (and be happy) and
> with those not catching it the "user code" can catch it as myOwn...

That doesn't change the basic problem for the container implementor: a
standard-defined container can catch std::bad_alloc, which will also
catch exceptions implicitly convertible to std::bad_alloc, but not in
such a way that conformance with container requirements would be
compromised if the allocator decides to throw something else instead. If
Container::insert() has done anything to the container which would have
to be undone, before the call to Allocator::allocate(), it must capture
all exceptions, not just std::bad_alloc (though it is free to treat
bad_alloc in a seperate catch block, if it wishes).

> Only interesting issue is: are the STL containers allowed to re-throw
> this bad_alloc?  I mean required, not allowed.  Or how will the client

I'm certain they are not required to rethrow it. The only thing I am
unsure of is whether they're allowed to rethrow it.

> code _easily_ and _bullletproof_way_ know, that the insert has failed?
> I hate writing return code checks all over my C++ code: we have
> exceptions.

The exact wording is that "the function has no effects". I'm not clear
whether "no effects" prohibits the throwing of an exception.  If it
does, insert(p,t) must return, but is required to return an iterator
pointing at the place in the container where the iterator was inserted;
a requirement that can't be met. The most obvious thing to do is to
return end() to indicate failure of the insertion; it's the only special
value that could reasonably be used for that purpose. However, there's
nothing in the standard that says so.

std::deque<T,Allocator>::insert() and std::vector<T,Allocator>::insert()
are specifically prohibited from throwing anything "unless an exception
is thrown by the copy constructor or assignement operator of T", so this
issue certainly applies to those containers.

For associative containers, single item insert() returns a
std::pair<iterator,bool> where the 'bool' indicates whether the insert
succeeded. It's still unclear what the iterator value should be if it
failed, but the bool at least allows you to avoid that issue.


> _If_ the STL rethrows the bad_alloc after cleaning up, we can catch it
> as myOwnBadAlloc all the time and act accordingly.  Would be nice.

That would only work if there's an implicit conversion from bad_alloc to
myOwnBadAlloc. If slicing occurs, the exception that gets re-thrown
would be the exception that was caught, not the exception which was
thrown. Now, if you caught bad_alloc&, it would be a different story.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: howie@mathworks.com (Howard Taitel)
Date: Tue, 14 Aug 2001 23:26:13 GMT
Raw View
Is it legal to write an allocator that throws something other than
bad_alloc upon failure?  In other words, does the STL code ever
explicitly try to catch bad_alloc?

Thanks in advance.

--Howie

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "James Russell Kuyper Jr." <kuyper@wizard.net>
Date: Wed, 15 Aug 2001 16:29:09 GMT
Raw View
Howard Taitel wrote:
>
> Is it legal to write an allocator that throws something other than
> bad_alloc upon failure?  In other words, does the STL code ever
> explicitly try to catch bad_alloc?

In section 20.1.5, Table 32 only specifies that allocate() may throw "an
appropriate exception". It doesn't specify what that exception would be.
All of the standard-defined containers are required to accept and work
properly with any user-provided allocator that meets the requirements
listed in 20.1.5.

Therefore, a standard-defined container may only catch bad_alloc if
doing so doesn't make it violate the standard's requirements for that
container if the allocator decides to throw something else instead.

I won't bother trying to figure out the all of the implications of that
fact, but there certainly are some. For instance, if any exception
thrown during an insert() of a single object into a sequence container,
then insert() is required to have no effect. Therefore, if insert()
makes any changes to the container before calling allocate(), it has to
catch all possible exceptions thrown by allocate(), and in the exception
handler undo whatever it changes it made. It can't make do by catching
only bad_alloc. It can't even make do by catching std::exception&, since
there's no requirement that the relevant exception is derived from
std::exception.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Attila Feher <Attila.Feher@lmf.ericsson.se>
Date: Thu, 16 Aug 2001 11:00:41 GMT
Raw View
"James Russell Kuyper Jr." wrote:
>
> Howard Taitel wrote:
> >
> > Is it legal to write an allocator that throws something other than
> > bad_alloc upon failure?  In other words, does the STL code ever
> > explicitly try to catch bad_alloc?
>
> In section 20.1.5, Table 32 only specifies that allocate() may throw "an
> appropriate exception". It doesn't specify what that exception would be.
> All of the standard-defined containers are required to accept and work
> properly with any user-provided allocator that meets the requirements
> listed in 20.1.5.
>
> Therefore, a standard-defined container may only catch bad_alloc if
> doing so doesn't make it violate the standard's requirements for that
> container if the allocator decides to throw something else instead.
>
> I won't bother trying to figure out the all of the implications of that
> fact, but there certainly are some. For instance, if any exception
> thrown during an insert() of a single object into a sequence container,
> then insert() is required to have no effect. Therefore, if insert()
> makes any changes to the container before calling allocate(), it has to
> catch all possible exceptions thrown by allocate(), and in the exception
> handler undo whatever it changes it made. It can't make do by catching
> only bad_alloc. It can't even make do by catching std::exception&, since
> there's no requirement that the relevant exception is derived from
> std::exception.
[SNIP]

What about inheriting this "myOwnBadAlloc" from bad_alloc?  In this case
the STL which looks out for bad alloc can catch it (and be happy) and
with those not catching it the "user code" can catch it as myOwn...

Only interesting issue is: are the STL containers allowed to re-throw
this bad_alloc?  I mean required, not allowed.  Or how will the client
code _easily_ and _bullletproof_way_ know, that the insert has failed?
I hate writing return code checks all over my C++ code: we have
exceptions.

_If_ the STL rethrows the bad_alloc after cleaning up, we can catch it
as myOwnBadAlloc all the time and act accordingly.  Would be nice.

Attila

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]