Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use the STL if I cannot afford the slow performance when exceptions are thrown?

For example, I'm writing a multi-threaded time-critical application that processes and streams audio in real-time. Interruptions in the audio are totally unacceptable. Does this mean I cannot use the STL because of the potential slow down when an exception is thrown?

like image 785
Carl Avatar asked Oct 02 '08 20:10

Carl


3 Answers

Generally, the only exceptions that STL containers will throw by themselves is an std::bad_alloc if new fails. The only other times are when user code (for example constructors, assignments, copy constructors) throws. If your user code never throws then you only have to guard against new throwing, which you would have had to do anyways most likely.

Other things that can throw exceptions: - at() functions can throw std::out_of_range if you access them out of bounds. This is a serious program error anyways.

Secondly, exceptions aren't always slow. If an exception occurs in your audio processing, its probably because of a serious error that you will need to handle anyways. The error handling code is probably going to be significantly more expensive than the exception handling code to transport the exception to the catch site.

like image 173
Greg Rogers Avatar answered Oct 29 '22 04:10

Greg Rogers


If an STL container throws, you are probably having much bigger problem than the slow down :)

like image 36
Nemanja Trifunovic Avatar answered Oct 29 '22 02:10

Nemanja Trifunovic


It's not clearly written in the previous answers, so:

Exceptions happen in C++

Using the STL or not won't remove the RAII code that will free the objects's resources you allocated.

For example:

void doSomething()
{
    MyString str ;
    doSomethingElse() ;
}

In the code above, the compiler will generate the code to free the MyString resources (i.e. will call the MyString destructor), no matter what happens in the meantime including if if an exception is thrown by doSomethingElse or if you do a "return" before the end of the function scope.

If you have a problem with that, then either you should revise your mindset, or try C.

Exceptions are supposed to be exceptional

Usually, when an exception occurs (and only when), you'll have a performance hit.

But then, the exception should only sent when:

  • You have an exceptional event to handle (i.e. some kind of error)
  • In very exceptional cases (i.e. a "massive return" from multiple function call in the stack, like when doing a complicated search, or unwinding the stack prior a thread graceful interruption)

The keyword here is "exceptional", which is good because we are discussing "exception" (see the pattern?).

In your case, if you have an exception thrown, chances are good something so bad happened your program would have crashed anyway without exception.

In this case, your problem is not dealing with the performance hit. It is to deal with a graceful handling of the error, or, at worse, graceful termination of your program (including a "Sorry" messagebox, saving unsaved data into a temporary file for later recovery, etc.).

This means (unless in very exceptional cases), don't use exceptions as "return data". Throw exceptions when something very bad happens. Catch an exception only if you know what to do with that. Avoid try/catching (unless you know how to handle the exception).

What about the STL ?

Now that we know that:

  • You still want to use C++
  • Your aim is not to throw thousand exceptions each and every seconds just for the fun of it

We should discuss STL:

STL will (if possible) usually verify if you're doing something wrong with it. And if you do, it will throw an exception. Still, in C++, you usually won't pay for something you won't use.

An example of that is the access to a vector data.

If you know you won't go out of bounds, then you should use the operator [].

If you know you won't verify the bounds, then you should use the method at().

Example A:

typedef std::vector<std::string> Vector ;

void outputAllData(const Vector & aString)
{
   for(Vector::size_type i = 0, iMax = aString.size() ; i != iMax ; ++i)
    {
       std::cout << i << " : " << aString[i] << std::endl ;
    }
}

Example B:

typedef std::vector<std::string> Vector ;

void outputSomeData(const Vector & aString, Vector::size_type iIndex)
{
   std::cout << iIndex << " : " << aString.at(iIndex) << std::endl ;
}

The example A "trust" the programmer, and no time will be lost in verification (and thus, less chance of an exception thrown at that time if there is an error anyway... Which usually means the error/exception/crash will usually happen after, which won't help debugging and will let more data be corrupted).

The example B asks the vector to verify the index is correct, and throw an exception if not.

The choice is yours.

like image 33
paercebal Avatar answered Oct 29 '22 03:10

paercebal