-2

I saw a function that uses throw to return something.

I've made some research before asking this, here, about throw and I did not find very much.

If someone could explain me when to use throw to return something and when to use the normal return statement, that would be awesome.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
XBoom
  • 91
  • 1
  • 1
  • 6
  • 1
    FYI: C++ plus Windows Forms is probably C++/CLI and not C++. – crashmstr Dec 14 '17 at 18:51
  • 2
    Possible duplicate of [What happens when I throw an exception?](https://stackoverflow.com/questions/3065284/what-happens-when-i-throw-an-exception) – Mathews Sunny Dec 14 '17 at 18:51
  • 2
    `throw` is used to throw an exception. You can read about exceptions in your [C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). OT: C++ doesn't have Windows Forms. You might be using C++/CLI, **not** C++. – Algirdas Preidžius Dec 14 '17 at 18:51
  • `throw` "throws" an error, and will be caught in a `catch`. The `catch` could be a long way away. `return` just returns to the caller. Different mechanism and different reasons for using. – crashmstr Dec 14 '17 at 18:52
  • Please study the language by reading a [good book on the subject](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) and not by 'messing around'. – SergeyA Dec 14 '17 at 18:54
  • @Cheersandhth.-Alf I believe, a lot of downvotes came at the earlier version of the question, beginning with words 'I was messing around'. People tend to dislike questions which suggest OP is learning the language by trial and error. – SergeyA Dec 14 '17 at 19:22

4 Answers4

1

Using throw to return a result can be useful in a deeply nested recursion. Instead of backing out of each call level you get right back up to the top level call for this goal. I think in most other situations it's both too inefficient (because exceptions are optimized for failure handling) and too unconventional to even consider.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 3
    I did not downvote, but if I were you, I would fully expect some criticism. The mantra 'do not use exceptions for flow control' is pretty much a law nowadays. – SergeyA Dec 14 '17 at 19:11
  • This is the same as `goto`. Utterly reviled, but still very useful in rare and controlled circumstanced. As an answer to "Why was this weird thing done and how can I take advantage of it?" this is a good answer. – user4581301 Dec 14 '17 at 19:25
  • @user4581301 While `goto` is an ugly beast and has earned its reputation for being sinister, it is fast. Exceptions aren't necessarily as lightweight, they can impose a lot of overhead depending on what kind of exception you're popping and how you're rescuing it. If I had to choose between exceptions and a `goto` because there was no other way, sadly `goto` would win. If you want to get *really* ugly you can use [`longjmp`](http://en.cppreference.com/w/cpp/utility/program/longjmp). – tadman Dec 14 '17 at 19:47
  • @tadman: Note that `longjmp` is incompatible with C++ RAII. E.g. local `std::string` variables might leak. Part of the apparent inefficiency of a `throw` is that it unwinds the stack call frame by call frame (possibly skipping those where no cleanup is necessary). – Cheers and hth. - Alf Dec 14 '17 at 19:53
  • @Cheersandhth.-Alf I'm not disagreeing. Every time I see code with `longjmp` in it I end up filled with dread. It's never a good thing. – tadman Dec 14 '17 at 20:03
0

throw isn't used to return any value , it is used to throw exceptions i.e. if you think that a certain condition in the program is going to cause a runtime error or malfunction then you throw a exception which helps to avoid and deal with such runtime errors. Return is used to return from a function and a value to the calling function.

  • You can place all sorts of interesting information you want `return`ed inside the thrown exception. Usually not a good idea, returning via exception, but it can be done. – user4581301 Dec 14 '17 at 19:27
0

return is the easiest and in many situations also the most efficient way to return a computed value, a reference to a class member, a state information (e.g. an enum value), a trivial success/failure information, and, and, and. So this is the most common and usual way to evaluate function values.

throw on the other hand (like Alf already answered) deals with exception's - which, as the name already pretty clearly states :) an exception of the normal control flow: "Something very important (often something bad) happened, which requires an instant handling, I can not continue my usual processing flow and have to throw an exception immediately.". The reason can sometimes be a catastrophic and unrecoverable state in the program, but by no means always. For example, a socket losing its connection is pretty common and not a catastrophy - but can be a reason for throwing an exception nevertheless, because the socket code may be not able to continue computing.

Exceptions are usually a bit more difficult to handle - and to integrate into your program design - than usual return values, and they are - as others already stated - less efficient than simple return values, but they have a lot of benefits.

They can be caught from anywhere in the stack of calling functions Let's say you write a game, with a game engine (e.g. Ogre), and this engine uses a direct X interface. Now something deep, deep in the DirectX interface happens, which hinders the engine from working correctly. The error handling of this function (may be 8-10 calls deep in the call stack), which can not work properly anymore, would be nearly impossible if it would be done with normal return values - both for the engine programmers and for the game programmer. So in that case, without exceptions, the method of choice would be a non-standardized error handler - pretty similar to an exception, but not with the powerful possibilities of exceptions. Here's a practical example on how to handle this error with an exception (please ignore the real purpose of the functions, it's just to show the principle:

        try 
        {
            mHOQList[mCurrentFrame]->endOcclusionQuery();
        } catch( Ogre::Exception& e )
        {
            if( e.getNumber() == Exception::ERR_RENDERINGAPI_ERROR
            && stdEx::string(e.getDescription()).beginsWith( "End occlusion called" ))
            {
                // a device lost occurred during our occlusion query. Simply ignore it.
                return true;
            }
            else
                throw;

        }

We are doing an occlusion query here, which we know can not continue when a "device lost" event happens during it's operation. So we place it in a try/catch clause. When everything works out good in the endOcclusionQuery(), the catch() is never called, and everything is fine. If an exception is thrown, we first check if we can handle it. We check the number of the exception and its description. If these informations have a specific value, we know that it's a benign error, we can safely ignore it and carry on the next frame. If we don't know how to handle it, we simply throw;, which leaves the handling of the exceplion to a catch() lower in the call hierarchy, which brings me to the next points:

They can be evaluated selectively. The example above will catch and handle exceptions of the type Ogre::Exception, but nothing else. A std::exception or another exception type is not caught. Let's say for example the endOcclusionQuery() calls a callback in our own code, which then also gets into an exceptional state and throws. We would let this exception pass by and leave it to the lower (or higher) levels of the call hierarchy to handle it.

They can be rethrown. In the example, we use throw; to re-throw and pass the handling to lower levels in the call hierarchy.

They can be stored and even re-thrown in a separate thread Imagine a library with hundreds of worker threads, and a manager thread which coordinates these threads. Since exceptions are bound to a single thread, so the manager thread can never catch exceptions from the worker threads. But the worker threads can catch their own exceptions and either handle them if possible or store them, pass them to the manager thread, where it can be rethrown and be handled by the manager thread.

They can be thrown in Constructors Constructors have no return value, and so it is impossible to check its success with return values. State members are possible, but awkward - they tend to be overlooked. So the preferrable way to deal with errors in a constructor is to throw (of course as a documented behavior). See also Throwing exceptions from constructors

They are standardized Well when it comes to this, the example above is not the best. Ogre is a pretty old engine, long before C++11, and so the exception classes are proprietary. You can throw anything - from a char to a class LiverSausage. But today this shouldn't be done anymore - std::exception is the class of choice. It contains everything which is needed for a simple exception, and can be inherited for more sophisticated exceptions. It is commonly used and inherited in the STL, and there are helpers classes and functions like std::exception_ptr, std::current_exception() etc.

They can be used as a safe bailout for an unrecoverable program error. At the end, something ugly like this unfortunately can happen in the best programs. You can throw this fatal exception anywhere in your program, and you can catch this exception at a single place, where you can log the error, evaluate where it came from, perhaps even write a dump - so you have at least a clue what could have happened, which is at least less worse than simply crashing ;)

user2328447
  • 1,807
  • 1
  • 21
  • 27
0

While this might sound bad, I actually let performance be a strong factor in guiding this decision. Most modern optimizers implement what's called zero-cost exception-handling, which ultimately translates to something like, "branch-free normal execution paths, but expensive exceptional paths".

It makes throwing quite expensive in exchange for making your normal execution paths really cheap. I don't have precise numbers for the costs but it's probably relatively extremely expensive if you're using a try/catch block just to test if a key exists in a data structure, e.g.

The other guiding force that I've found useful is the idea of an external exception outside of the programmer's control. Examples of that might be a client failing to connect to a server which should be up after repeated attempts, encountering a corrupt file, failing to allocate memory, things of this sort.

I did get into a debate one time with a colleague about whether a user jamming an abort button on a progress bar qualifies as an exceptional circumstance. I really thought it did because the operation is normally supposed to succeed, and a user aborting is a truly exceptional circumstance outside of the developer's control. On top of that it really simplified the code quite a bit over trying to propagate an abort status down the entire call stack.

In these cases where people might not agree about what is and isn't exceptional control flow, I use performance as like the deciding factor. Here throwing to abort an expensive operation isn't a big performance overhead, since it's not like we're throwing a million times in a critical loop. We're just throwing one time to abort a very expensive operation, and there the overhead of throwing becomes quite trivialized. So that's what I mean when I talk about performance being a deciding factor.