olga
olga

Reputation: 11

looking for a good solution for no exceptions array

If I'm not mistaken, both std::array/vector throw exceptions. is it possible to eliminate that? for example, I know that I can add nothrow to new so it won't throw an exception, just return null.

I need to use some type of array, and I prefer some std version instead of just new[] version but don't want to get exceptions involved. can you maybe recommend a good option?

Upvotes: 1

Views: 1012

Answers (1)

Mats Petersson
Mats Petersson

Reputation: 129504

Technically not an answer the the original question beyond "it's not possible" suggested by Snowman in the comments of the deleted answer. However I do hope that I can offer some advice on solutions, as well as the philosophy and thoughts behind the "no exceptions" policy, which could be used to argue for the use of std::vector as a good thing, not a thing to be avoided. Obviously, it is up to the reader to determine if such an argument is likely to lead to a positive or not so positive outcome both for the reader as an individual and the project.

The purpose of "no exception" rules in coding standards is typically there to avoid the rather messy situation where there are LOTS of different exceptions, that are handled at various levels, and the code gets rather hard to read - it can be hard to manage that, and is a reasonable reason for "must not throw exceptions".

If this is the purpose (rather than for example "we're using a compiler that doesn't support exceptions, because it's the only one supporting the processor X that we need to compile for"), then I would argue that using std::vector and std::map should still be allowed, perhaps with a try ... catch inside main [or similar central place] that catches all exceptions and reports the exception in a reasonably user-friendly manner, then exits - because your code will not "be right" if you do run into the situations where std::vector throws excptions - it is not part of "normal operation" to run out of memory or access out of range elements in the container.

Note also that it's not STL that must be avoided if you have a strict "no exceptions" rule, but also ALL calls to new [except for the new nothrow variety] - more on this below.

There is another situation where exceptions are "exceptionally bad", and that is where the C++ code is called from C - in which case, it's undefined behaviour to have exceptions "leak" from C++ into C-code (because the runtime won't know how to deal with the exception when walking up the stack to find the handler in this case).

If the rule is strictly "you can't use ANY functionality in C++ that may throw exceptions", then nearly all of the standard template library (and a lot more) are out of scope. You'll have to search the web for other alternatives [sorry, can't provide any meaningful help here] and write a lot of code like this:

some_vector_that_without_exceptions<int> v;
...
result = v.insert(element);
if (result != GOOD) 
    ... whatever you do when you can't insert to vector ... 
else 
    ... continue as you were ... 

I have the joy of programming under a "no goto, no early return" guideline at work - which makes sense, but you do get a fair chunk of repetition of:

result = some_thing(...);
if (result != success)
{
   ... cleanup ...
}
else 
{
    result = next_thing(...);
    if (result != success)
    {
       ... same cleanup as above ... 
       ... clean up after next_thing ... 
    }
    else
    {
        ... more stuff like above ...
    }
}

It gets rather tedious after a while, but such is life working with coding standards at times.

Since the main reason for STL containers throwing exceptions is new and delete, it is possible, depending on what you actually wish to have happen when the system runs out of memory, that writing your own operator new (a trivial version here) would solve this problem:

void *operator new(size_t size)
{
    void *p = malloc(size);
    if (p == NULL) 
    { 
       ... do something, like report out of memory and exit ...
    }
    return p;
}

void operator delete(void *p)
{
    free(p);
}

// And similarly for new [] and delete [].

That will avoid ALL throwing behaviour from inserting/resizing for example std::vector or std::map [although, of course, std::vector::resize will still have a throw marker on it, since the header file won't know that your operator new will never throw an exception - but in practice, it won't happen, and it's practically the only reason that the STL containers will throw exceptions "under normal circumstances" (that is, not out of range access, etc).

Upvotes: 3

Related Questions