May STL iterator methods throw an exception - c++

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.

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.

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

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.

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.

Related

Is std::vector exception neutral?

Exception for the member function at(), I cannot think of exceptions being thrown by std::vector functions but by its allocator or by its elements constructors and assignment operators. Therefore, exception neutrality can be a very desirable guarantee when implementing your own allocators. For example, you might allocate all required memory up-front and then rely on the noexcept guarantee of an allocator to propagate to its container.
Does the C++ standard provide exception neutrality of std::vector<T,Alloc>?
Besides memory allocations, there is one situation where vector itself will also throw exceptions: the at() member function.
So, after reserve()ing sufficient memory, you are guaranteed that no exceptions will be thrown, provided that the vector's class's constructors and assignment operators (which will be called as part of modifying the vector) do not throw any exceptions either, and there are no out of range calls to at().

std::terminate and destructors of empty containers

Consider some standard container which uses dynamic memory (i.e. is an AllocatorAwareContainer) and has a size and capacity of zero. For example, take a std::vector and call vec.resize(0); vec.shrink_to_fit();.
I would imagine that such container instances would contain only nullptr pointers for their logical contents and std::size_t members to track information like size. I would also imagine that their destructors would do essentially nothing, as there is no dynamic memory to be freed.
All destructors of containers, as I know, are noexcept. I.e. on throwing of an exception during destruction they should call std::terminate. It is possible in case of Allocator::deallocate() throw exception.
Can I be sure containers in the state, described above, never call std::terminate on destruction?
It is possible in case of Allocator::deallocate() throw exception.
No, it's not. The requirements for Allocator forbid deallocate to throw. It's not a formal noexcept specifier, but C++14 Table 28 Allocator requirements says:
a.deallocate(p, n) [...] Does not throw exceptions.
So if your allocator throws on deallocation, that's a violation of the required contract and all bets are off anyway.

How can an implementation guarantee that copy constructor of an iterator is no throw?

Clause 23.2.1.10 of C++11 standard says that
"no copy ctor of a returned iterator throws an exception"
Does this basically state that is it possible for a copy ctor of an iterator not to throw even a bad_alloc presumably (leaving the case where iterator could be just a pointer and here no issues) because it will use the information already constructed in the "returned iterator"? because it is passed by value will the stack be allocated in the called function hence can guarantee no memory issues ?
That paragraph talks about the iterators used by the containers in the standard library. These iterators are known to be implementable in ways so that they don't throw exception while being copied. For example, none of them have to use any dynamically allocated memory.
The guarantee is just for these iterators, not for iterators in general (even though it is a good idea to follow the example).
Legal answer: no. Thtat's just your interpretation. It is technically correct, but it may be not the one and only technically correct interpretation.
Technical answer: The point, here, is avoid that an exception thrown by a mutating iterator (think to an inserter or to an output iterator) causes an algorithm to be abandoned while letting a container in an undefined and inconsistent state (think, for example, to a linked list with the links not yet completely re-linked)
It's not just a matter of bad_alloc for iterators that have a dynamically allocated state, but also of an iterator that -during it's own copy- tries to modify a referred item failing in that (for example, because the item assignment throws).
When such a case happens, the iterator is not required to "complete the algorithm" (that would be impossible) but to left the container in a consistent and still manageable state.
I think there is a misinterpretation about the scope of what copy constructor means.
A copy constructor is not responsible for allocating the memory where the object itself will be built, this is provided externally, by the caller.
The requirement, therefore, is that the body of the copy constructor (be it written or generated) does not throw. It is known in C++ that built-in types (int, T*, ...) can be copied without throwing, and from there one can built types that are thus copyable without throwing exceptions (as long as one avoids dynamic resource allocation and/or IO it's automatic).

Can any C++ 98 standard container operations throw std::bad_alloc?

I was trying to work out if the try catch is needed in the following code:
std::vector<int> values;
// ignore that this can throw std::bad_alloc
values.push_back(1);
try {
for (std::vector<int>::iterator iter = values.begin();
iter != values.end(); ++iter) {
++(*iter);
}
} catch (const std::bad_alloc&) {
// Is this needed?
}
Looking through the C++ 1998 standard the only thing I can find which hints at this is section 23.1 "Container requirements" bullet point 8 which contains the sentence:
A copy of this argument is used for any memory allocation performed, by these constructors and by all member functions, during the lifetime of each container object.
My interpretation of this is that any member function in a container can call the allocator so any member function can throw std::bad_alloc. Am I being overly paranoid or is this really the case?
If you carry on reading a bit further, you'll find 23.1/10, which gives the containers' requirements regarding when exceptions can be thrown, in particular:
no erase(), pop_back() or pop_front() function throws an exception.
no copy constructor or assignment operator of a returned iterator throws an exception.
If you're truly paranoid, then you should consider the possiblity of begin() and end(), and even iterator increment, throwing; but there's no need for them to do anything complicated in any sane implementation of the standard containers.
Theorotically Yes, any standard library container member function can throw bad_alloc.
Most standard Containers themselves do not throw any exceptions except (std::vector::at()) but they can throw exceptions for memory allocation failures or exceptions of user-defined operations.
I assume your fear is that push_back() throws in your example case, if not then yes you are being paranoid. Eventhough, it is an implementation detail In practice almost none of the implemenatations will try to allocate if you are just getting iterators(begin(), end()).
I didn't find something more specific in the standard, so in the absence of evidence we 'll have to conclude that technically any container method can throw bad_alloc.
I wouldn't worry about begin and end throwing as far as the container itself is concerned, but there's another troubling point: iterator implementation. If iterators are of class type then theoretically the construction (or assignment) of such instances could very well throw. So while I don't think it's probable that any randomly chosen standard library implementation would throw, you can't really rule it out.

Are C++ Containers exception-safe?

I use the implicit Constructor and a load() Member which inputs the Attributes, but can also throw exceptions.
My question is: if the Attributes are everyday C++ Containers will I get memory leaks if exceptions happen in load()?
Thank you for reading.
Edit: example code to help clarify my question.
class One
{
public:
std::vector<int> stuff;
void load() {
stuff.resize(13);
stuff[0] = 43;
std::bad_alloc ba;
throw ba; // will this cause memory leaks? (as far as this class is concerned)
}
}
I know this is a silly question but I had to ask it.
The container itself is exception safe.
But it also depends on the type being placed in the contain and if it has been written correctly.
i.e.: Exceptions should not escape the destructor
The standard defines the following guarantees on containers and exceptions:
23.2.1 General container requirements [container.requirements.general]
Paragraph 10:
Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.3.4, and 23.3.6.5) all container types defined in this Clause meet the following additional requirements:
— if an exception is thrown by an insert() function while inserting a single element, that function has no effects.
— if an exception is thrown by a push_back() or push_front() function, that function has no effects.
— no erase(), clear(), pop_back() or pop_front() function throws an exception.
— no copy constructor or assignment operator of a returned iterator throws an exception.
— no swap() function throws an exception.
Yes, containers are exception safe. As long as you aren't doing shenanigans like allocating them on the heap (without exception-safe smart pointers) or such like that, you'll be fine.
Since your question doesn't state much, here is my take.
If you are allocating memory using new/new[] (inside your load()) then you have to deallocate using delete/delete[], when exception is thrown.
If you are allocating as an automatic variable then they are exception safe.