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

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.

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::set::find exception guarantees

I'm currently writing exception-safe code and my design requires no throw guarantee for
set::find method.
I assume the comparator object always succeeds.
Does it imply set::find method will always succeed?
I thought about such a possibility after I have seen that according to http://en.cppreference.com/w/cpp/container/set/erase, set::erase method, with the same assumption, should always succeed and maybe there's a find in it (then it would be definetely worth a comment in documentation!)
The direct source for the problem is that I need to check whether an element is in a set and remove it from the set -- all that having no throw guarantee (it's in a catch block).
std::set::find:
Return value
Iterator to an element with key key. If no such element is found, past-the-end (see end()) iterator is returned.
Neither the documentation nor the C++ Standard explicitly list any exception safety guarantees. However, the same rules spelled out for std::set::erase apply here (§23.2.4.1 Exception safety guarantees [associative.reqmts.except]):
erase(k) does not throw an exception unless that exception is thrown by the container’s Compare object (if any).
In essence, unless the Compare object throws an exception, std::set::find does not throw. Bjarne Stroustrup has the following to say in The C++ Programming Language, Special Edition - Appendix E:
Fortunately, predicates rarely do anything that might throw an exception. However, user-defined <, ==, and != predicates must be taken into account when considering exception safety.
If you aren't providing any user-defined predicates you can assume std::set::find does not throw an exception. If you are, you should mark them as noexcept to work safely in your scenario.
C++11 §23.2.4.1 Exception safety guarantees [associative.reqmts.except] lists all the exception safety requirements for associative containers (including set) and there is no mention made of find. So no, the standard does not guarantee that find never throws.
In the absence of undefined behavior and assuming a non-throwing comparator, I find it extremely unlikely that an implementation of the C++ standard library exists which will throw an exception from set::find. I would personally be comfortable with (a) wrapping set::find in a noexcept forwarding function so that the program will crash if such an "impossible" thing ever occurs, or (b) wrapping a particular set::find call in
auto it = foo.end();
try {
it = foo.find(bar);
} catch(...) {}
and simply treating an exception as "not found."
Note that the ordering relation of associative containers is an easily-overlooked source of undefined behavior: § 23.2.4/2 requires the ordering relation to induce a strict weak ordering (as described in §25.4) on the key elements. An associative container instantiated with an ordering relation that is not a strict weak ordering does not have defined behavior, one possible outcome of which is throwing an exception from find.

May STL iterator methods throw an exception

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.

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.

Is std::vector::push_back permitted to throw for any reason other than failed reallocation or construction?

Consider:
std::vector<int> v;
v.reserve(1);
v.push_back(1); // is this statement guaranteed not to throw?
I've chosen int because it has no constructors that could throw - obviously if some copy constructor of T throws, then that exception escapes vector<T>::push_back.
This question applies as much to insert as push_back, but it was inspired by Is it safe to push_back 'dynamically allocated object' to vector?, which happens to ask about push_back.
In the C++03 and C++0x standard/FCD, the descriptions of vector::insert say that if no reallocation happens, iterators/references before the insertion point remain valid. They don't say that if no reallocation happens, no exception is thrown (unless from constructors etc of T).
Is there anything elsewhere in the standard to guarantee this?
I don't expect push_back to do anything that could throw in this case. The GNU implementation doesn't. The question is whether the standard forbids it.
As a follow-up, can anyone think of a reason why any implementation would throw? The best I can think of, is that if a call to reserve ends up increasing the capacity to a value in excess of max_size(), then insert perhaps is permitted to throw length_error when the max size would be exceeded. It would be useless to increase capacity beyond max_size(), but I don't immediately see anything forbidding that, either [Edit: your allocator would probably stop you increasing capacity beyond max_size, so this suggestion might be no good.]
Well, it kind of depends on the allocator you are using.
Apart from the allocator, the only thing you can rely on is that push_back() and push_front() are guaranteed to be noop if an exception is thrown (23.1-10). The standard definitely doesn't forbid the push_back() from throwing exceptions.