try catch finally - when doc->StartUndo()



  • On 06/08/2013 at 11:24, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:    
    Platform:      
    Language(s) :

    ---------
    I use try-catch-finally ALL the time when programming in Delphi and C#.
    For my plugins in C++, I haven't used it so far. All the examples in the SDK, I find no such thing..(?)
    Does it exist in C++?

    Take this scenario

      doc->StartUndo();
      do_something
      do_something_else
      something_goes_wrong
      do_the_final_thing
      doc->EndUndo();
    

    I am responsible for calling doc->EndUndo(), when I have called StartUndo(), right?
    I am interested to know how you guys solve this.



  • On 06/08/2013 at 16:43, xxxxxxxx wrote:

    Oh yes.  C++ has try-catch-all (no finally).  But, Cinema 4D's SDK does not directly support exception handling.  So, if you do use them, you must catch EVERY exception or it will wind back to the c4d_main of the plugin and crash Cinema 4D.  A suggestion on StackOverflow uses this construct (catch the exceptions you know about, then catch everything else) :

      
        
        
        try{
            // ...
        } catch (const std::exception& ex) {
            // ...
        } catch (const std::string& ex) {
            // ...
        } catch (...) {
            // ...
        }
    
    For StartUndo()/EndUndo(), to avoid early returns in a method, I wrap a method with these like so:  
    
      
        doc->StartUndo();  
        Bool retval = DoStuffThatHasUndos();  
        doc->EndUndo();  
        if (!retval) return;
    


  • On 06/08/2013 at 17:03, xxxxxxxx wrote:

    Hi,
    for the latter, I have already done that, so I can cater for the EndUndo();
    But regarding the exception handling, or the lack of such, I am still a bit confused.

    Take this:

    	int a = 123;
    	int b = 0;
    	try
    	{
    		int c = a / b;
    	}
    	catch(std::exception &e)
    	{
    		MessageDialog("Something went wrong");
    	}
    

    The MessageDialog never fires, instead Cinema will crash, regardless of wrapping this in a try - catch.
    How can I wrap stuff in a way that prevents a crash, and furthermore executes some code, in this case a simple message dialog?



  • On 06/08/2013 at 17:50, xxxxxxxx wrote:

    You really need to include the catch-all (catch (...)).  It is not guaranteed that every exception is derived from 'exception' or that it will be caught specifically.  See here:

    http://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero



  • On 06/08/2013 at 18:31, xxxxxxxx wrote:

    Hi Robert,
    thanks a lot! This was an important lesson. I have never seen catch(...) before, honestly. I thought it was a symbol for some code, since you used the three dots elsewhere too, but indeed, those three periods compile like magic 😉

    As a plugin writer, wouldn't you wrap everything, any method, in a try catch-all block? I see that almost everything is tested before being used, in the SDK plugins. So I have adopted that habit myself too, rigorously. But as an extra safety, why not also wrap it up in a try catch-all block? Are there drawbacks?



  • On 06/08/2013 at 18:56, xxxxxxxx wrote:

    You can if you like.  It would make sense to have the try/catch on everything when exception handling is present.  Stuff that doesn't throw exceptions just executes as it normally would.  But since you can also catch errors (such as the overflow and such), it would even work for code that doesn't implement exception handling directly.



  • On 07/08/2013 at 03:44, xxxxxxxx wrote:

    It would make sense to have the try/catch on everything when exception handling is present.

    Really ? 
    I don't think this is a good idea.

    IMHO  Exception should be used only if really really needed and as rare as possible.

    Why not use RAII for this ?

      
    class UndoRAII  
    {  
      BaseDocument *m_doc;  
    public:   
      UndoRAII(BaseDocument *doc) : m_doc(doc) {}  
      ~UndoRAII() { doc->EndUndo(); }  
    }  
    

    And the use in this way.

      
        
        
        {  
          doc->StartUndo();  
          UndoRAII undo_end1(doc);  
          
        
        
          do_something
        
          do_something_else
        
          something_goes_wrong
        
          do_the_final_thing  
        }  
        
      
    


  • On 07/08/2013 at 04:11, xxxxxxxx wrote:

    While I agree, if you are wanting to handle STL exceptions (and errors) you may want to brace code that has those possibilities - such as mathematical algorithms and such beyond the normal STL exceptions.  Otherwise, I have never seen any problems in bracing larger sections of code.  There might be a very small speed hit at most.



  • On 07/08/2013 at 04:27, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    It would make sense to have the try/catch on everything when exception handling is present.
    Really ?  
    I don't think this is a good idea.

    I agree with Robert here. It is a very good idea in C#, so why not in C++?
    "Things" will invariably happen, especially when users  are involved, - and they usually are.

    -Ingvar



  • On 07/08/2013 at 04:46, xxxxxxxx wrote:

    Yeah, i actually did that in order to deal with failed memory allocations and IO errors in my current project. Basically try/catch around some complicated computations. If e.g. std::bad_alloc is caught it would just unwind to the top level function and return INITRENDER_OUT_OF_MEMORY, without me having to clutter my code with checks for every little allocation :)

    Don't forget to enable exception handling in the compiler options though. It is disabled by default.

    Also, none of the C4D API functions throws exceptions, so you have to check for errors manually or write wrappers which throw exceptions.

    For something like the Undo, you could also use a pattern where some arbitrary code is executed on scope exit but without having to write a special class for RAII. For example http://code.google.com/p/scope-exit/
    or http://www.boost.org/doc/libs/1_54_0/libs/scope_exit/doc/html/index.html I never tried it but i figured it should work nicely with c++11 lambdas, etc.



  • On 07/08/2013 at 06:13, xxxxxxxx wrote:

    I think that both Visual Studio and Xcode will error during compilation if there is exception syntax and exception handling isn't enabled.  But good to note that it needs to be enabled nonetheless.



  • On 07/08/2013 at 06:25, xxxxxxxx wrote:

    I have exception syntax and do not get an error. And I have never turned exception handling on, in fact, I have no idea how it is done in Visual Studio. I take it for granted it is on..



  • On 07/08/2013 at 07:37, xxxxxxxx wrote:

    Sorry, i meant it is disabled in the cinema4dsdk project. In VC it is just a warning if exception syntax is used while compiler support is disabled.
    The setting is in the project properties page Configuration Properties/C/C++/Code Generation/Enable C++ Exceptions.



  • On 08/08/2013 at 00:02, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I agree with Robert here. It is a very good idea in C#, so why not in C++?

    Some food for thought why you should avoid exceptions whenever possible (and that 's just the beginning if you dig into it) :

    http://c2.com/cgi/wiki?AvoidExceptionsWheneverPossible
    http://c2.com/cgi/wiki?DontUseExceptionsForFlowControl
    http://programmers.stackexchange.com/questions/107723/arguments-for-or-against-using-try-catch-as-logical-operators
    http://stackoverflow.com/questions/1744070/why-should-exceptions-be-used-conservatively

    Best regards,

    Wilfried



  • On 08/08/2013 at 00:24, xxxxxxxx wrote:

    Right, but if you use anything (a third-party lib or the STL) that requires exception handling, then you MUST handle them or suffer the consequences (Cinema 4D crashes).  Not much choice there.



  • On 08/08/2013 at 01:14, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Right, but if you use anything (a third-party lib or the STL) that requires exception handling, then you MUST handle them or suffer the consequences (Cinema 4D crashes).  Not much choice there.

    Maybe a requirement for 3rd party libs but not necessarily for STL. For Win I know that you can turn it off (you've to use the #define _HAS_EXCEPTIONS 0 #define _STATIC_CPPLIB besides switching off exceptions) and for OS X I'm pretty sure you can too, as the LLVM compiler project (while using STL) has the rule of not using RTTI or exceptions (see: http://llvm.org/docs/CodingStandards.html#do-not-use-rtti-or-exceptions) :

    "These two language features violate the general C++ principle of "you only pay for what you use", causing executable bloat even if exceptions are never used in the code base, or if RTTI is never used for a class. Because of this, we turn them off globally in the code."

    Best regards,

    Wilfried



  • On 08/08/2013 at 02:06, xxxxxxxx wrote:

    Never knew about that (but then I don't use exception handling very often).  How is error handling done then?  Does this switch to an alternative codebase that returns errors instead?



  • On 08/08/2013 at 03:35, xxxxxxxx wrote:

    Yes scope-exit can be very helpful, but only if you use C++11.

    Here is how I would do it using my SCOPE_EXIT implementation.

      
    doc->StartUndo();  
    SCOPE_EXIT  { doc->EndUndo(); }  
    ...  
    



  • On 08/08/2013 at 03:39, xxxxxxxx wrote:

    Ok, I am not using exceptions as type checking or value approval. I use try-catch in case something goes wrong which I had not thought of beforehand.
    Some very good programmers will foresee any possible event and any bad function argument and any peculiar user behaviour and write the appropriate code to tackle this.
    While I am not such a good programmer, I instead type check and validate values as best as I can, then I want to wrap it up in try-catch for final safety. I just do not want my plugins to crash C4D.

    In C#, which is my job (C4D plugins is a hobby), everything  I write is wrapped in try-catch, sometimes also -finally. Mostly I benefit from this during development and debugging, because if reflection in C#, I immediately know what went wrong, and at what line in what class in what file it happened. The gioal is of course to have as few exceptions as possible in the final product. 
    And I have very seldom used exceptions to steer the program flow.


Log in to reply