19

Destructors may not throw exceptions (so stack unwinding can complete during exception handling), and must deallocate any resources allocated to the object (so no resources leak). A design for an object that contains several other objects (or is allocated several resources) might record pointers to them in an STL container. The destructor would therefore use the following iterator-related methods:

  • begin(), end() for the container
  • operator++ for a valid iterator
  • operator* or operator-> for a valid iterator

But to guarantee that the destructor both does not throw exceptions and deallocates its resources you would need to rely on those methods never throwing exceptions.

Is it safe to rely on those methods never throwing exceptions? It is hard to imagine a practical implementation that would throw exceptions, as under the hood an STL iterator is essentially a pointer. But does standard C++ require that those methods never throw exceptions? I've not found a clear statement in the C++ standard.


Edit: The interesting case is for C++ 03 when you want to have a container of pointers to resources. There are good reasons for doing this; for example, if you have polymorphic resources. As Björn Pollex points out in his answer, if you use a container of resources (such as a std::list< Resource >) rather than a container of pointers to resources, the destructor of the container will take care of destruction (deallocation) of the Resource objects for you.

Community
  • 1
  • 1
Raedwald
  • 40,290
  • 35
  • 127
  • 207
  • 3
    "as under the hood an STL iterator is essentially a pointer" - you should never rely on that assumption. The concept is based on pointer, but implementation not necessarily. – mloskot Oct 26 '11 at 12:57
  • Destructors may throw exceptions, actually... as long as they catch them :). The rule is "an exception can't *propagate out* of a destructor". – Kos Oct 26 '11 at 13:05
  • The rule isn't even that, it's "if an exception propagates out of a destructor, the program will `terminate` under certain conditions". And I think it may have UB under certain conditions too, if the destructed object is part of an array and/or container, I can't remember. Whether you consider `terminate` an acceptable demise for your program depends on the program, although obviously if you're writing components that are supposed to be easily re-usable then you'd avoid it. – Steve Jessop Oct 26 '11 at 13:06

4 Answers4

18

operator++ for a valid iterator

The C++ standard (I refer to N3290 draft) does not give nothrow guarantee for increment operator of iterators.

For example, std::istreambuf_iterator::operator++ effects in call to std::basic_streambuf::sbumpc. The sbumpc may call uflow which in turn may throw exception.

mloskot
  • 33,165
  • 10
  • 97
  • 122
  • I appreciate MSalters & Raedwald – mloskot Oct 27 '11 at 12:17
  • 2
    This is, however, specified behavior, i.e. it's required that `istreambuf_iterator::operator++` have this effect. But importantly, the operator should not throw an exception if `sbumpc` doesn't. This is generally true - an iterator over a defined range (a container) can't just arbitrarily throw an exception when incremented within that range. Otherwise, an implementation could simply _always_ throw an exception and still satisfy the requirements of the spec. – davmac Nov 21 '15 at 13:02
6

no copy constructor or assignment operator of a returned iterator throws an exception

That's from the C++03 standard. I don't think that the standard goes any further than that.

Btw. it's 23.1.10

Šimon Tóth
  • 33,420
  • 18
  • 94
  • 135
1

The destructor would therefore use the following iterator-related methods

No it would not. The destructor of that object would just call the destructor of the container, which would in turn be guaranteed to not throw an exception.

If you use RAII correctly, you will almost never run into a scenario where you have to explicitly release resources. This could be achieved by have the container store shared_ptr or unique_ptr, or by using something like Boost.Pointer Container.

Björn Pollex
  • 70,106
  • 28
  • 177
  • 265
  • In the case of a `std::vector< Resource >`, yes. But not in the case of `std::vector< Resource * >`. – Raedwald Oct 26 '11 at 12:24
  • @Raedwald: I have extended my answer. This scenario should be cover by using the appropriate classes for resource-management. – Björn Pollex Oct 26 '11 at 12:26
  • 1
    `shared_ptr`, `unique_ptr`, Boost: I'm asking about standard C++ 2003. – Raedwald Oct 26 '11 at 12:26
  • @Raedwald: Depending on which compiler(s) you use, you might have support for TR1. Then you could use `std::tr1::shared_ptr` out of the box. – Björn Pollex Oct 26 '11 at 12:36
  • 6
    @JoachimPileborg: You cannot put an `auto_ptr` into a standard container. – Björn Pollex Oct 26 '11 at 12:40
  • @BjörnPollex: Oops, my bad! Removed comment. – Some programmer dude Oct 26 '11 at 13:00
  • 1
    For the reasons that you may not create STL containers of `std::auto_ptr` see http://stackoverflow.com/questions/111478/why-is-it-wrong-to-use-stdauto-ptr-with-stl-containers – Raedwald Oct 27 '11 at 08:25
  • "The destructor of that object would just call the destructor of the container": that implies that the destructor of the container has a means for iterating through the container **without** the danger of throwing an exception. It is hard to imagine how that could be possible without providing a similar guarantee for the provided `::iterator` class. – Raedwald Oct 27 '11 at 08:54
  • @Raedwald: I don't know how Boost.Pointer Container does it, but they seem to handle it.. – Björn Pollex Oct 27 '11 at 08:59
  • @Raedwald: The Boost `shared_ptr` and `unique_ptr` classes are perfectly legal Standard C++03. – Puppy Oct 27 '11 at 11:41
0

According to http://www.tenouk.com/Module31.html these operations (for '*' and '->' it depends also on the type stored) are no throw for STL containers.

kitek
  • 117
  • 12