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.
Related
The Allocator concept and std::allocator_traits doesn't say whether allocate will throw or not.
So when I'm writing a container using allocators, how to know whether to check return type or use catch?
The table in the Requirements section of the page you reference gives quite enough information when it may throw exceptions and when it must not throw exceptions. Below is a quote when an allocator may throw exceptions.
a.allocate(n) allocates storage suitable for n objects of type T, but does not construct them. May throw exceptions.
What type of exceptions is thrown is not described there and maybe is implementation dependent. Generally it is std::bad_alloc in STL.
Yes, it may throw. And the exception is std::bad_alloc since it use the allocator passed to it while std::allocator will throw std::bad_alloc.
In the page you refered introduces two scenarios:
Calls a.allocate(n)
Additionally passes memory locality hint hint. Calls a.allocate(n, hint) if possible. If not possible (e.g. a has no two-argument member function allocate()), calls a.allocate(n)
so basically you can turn to this:
http://en.cppreference.com/w/cpp/memory/allocator/allocate
After std::vector::resize() throws a std::bad_alloc exception, is the original data still valid and accessible in the std::vector object?
Does the answer hold for other allocators, e.g. if boost::interprocess::allocator is used as the allocator, and boost::interprocess::bad_alloc is thrown?
std::vector::resize is exception safe.
If an exception is thrown, this function has no effect (strong exception guarantee).
Link to the exception specification. The specification doesn't mention any particular requirement on the allocator and must hold regardless of the allocator you provide.
is the original data still valid and accessible in the std::vector object?
Yes, std::vector::resize has strong exception guarantee (except for the case mentioned as follows). §26.3.11.3/15 vector capacity [vector.capacity]:
If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.
The guarantee has nothing to do with what kind of allocator is specified; so it's always true.
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().
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.
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.