tags:

views:

352

answers:

9

I'm writing a reactive software, which repeatedly recieves input, processes it and emits relevant output. The main loop looks something like:

initialize();
while (true) {
    Message msg,out;
    recieve(msg);
    process(msg,out);
    //no global state is saved between loop iterations!
    send(out);
}

I want that whatever error occured during the proccess phase, whetehr it is out of memory error, logical error, invalid assertion etc, the program will clean up whatever it did, and keep running. I'll assume it is invalid input, and simply ignore it.

C++'s exception are exceptionally good for that situation, I could surround process with try/catch clause, and throw exception whenever something goes wrog. The only thing I need to make sure that I clean up all my resources before throwing an exception. This could be verified by writing a global resource allocator, and use it exclusively for all resources.

Socket s = GlobalResourceHandler.manageSocket(new Socket());
...
try {
    process(msg,out);
catch (...) {
    GlobalResourceHandler.cleanUp();
}

However, using exception is forbidden in our coding standard (also in Google's C++ standard BTW), as a result all the code is compiled with exceptions off, and I believe nobody's going to change the way everything work just for my design problem.

Also, this is code for embedded platform, so the less C++ extra feature we use, the faster the code becomes, and the more portable it is.

Is there an alternative design I can consider?

update: I appreciate everyones answer about idiotic code standard. The only thing I can say is, in big organizations you have to have strict and sometimes illogical rules, to make sure no idiot would come and make your good code unmaintainable. The standard is more about people than about technicalities. Yes, bad man can make every code a mess, but it's much worse if you give him extra tools for the task.

I'm still looking for a technical answer.

A: 

If you are running under windows, you could use SEH exceptions. They also have the advantage of pre-stack-unwind handler which can stop unwind (EXCEPTION_CONTINUE_EXECUTION).

Pavel Radzivilovsky
I'd imagine that if C++ aren't allowed, then SEH one's won't be either, especially seeing as they won't clean up the stack unless you've also got C++ exception handling enabled.
Joe Gauterin
A: 

Off the top of my head, you might be able to achieve something similar with signals.

Set up a signal handler to catch appropriate signals and have it clean things up. For example, if your code generates a SIGSEGV as a result of something that would otherwise have thrown an exception a little earlier, you can try catching it with the signal handler.

There may be more to it than this as I have not thought it through.

Hope this helps.

Sparky
I don't think you really want to catch segmentation violations. It's entirely possible that the heap or stack is corrupt.
JeremyP
A: 

Do you call any libraries that could raise exceptions? If it's the case, you will need a try catch anyway. For your internal errors, each method will need to return an error code (use return only for error code, use reference parameters to return the actual values). If you want to make memory cleanup 100% reliable, you could start your application using a monitor application. If your application crash, the monitor start it again. You still need to close files and DB connection, tho.

Simon T.
+6  A: 

If you can't throw an exception, then the alternative is to return (or to return false or similar error code).

Whether you throw or return, you still use C++ deterministic destructors to release resources.

The one thing that you can't easily just 'return' from is a constructor. If you have an unrecoverable error in a constructor, then it's a good time to throw; but if you're not allowed to throw, then instead you must return, and in that case you need some other way to signal construction failure:

  • Have private constructors and static factory methods; have the factory method return null on construction failure; don't forget to check for a null return when you call a factory method
  • Have a "get_isConstructedOk()" property which you invoke after each constructor (and don't forget to invoke/check it on every newly-constructed object)
  • Implement 'two-stage' construction: in which you say that any code which might fail mustn't be in a constructor, and must instead be in a separate bool initialize() method that's called after the constructor (and don't forget to call initialize and don't forget to check its return value).
ChrisW
+5  A: 

Just because using exceptions is forbidden in your current coding standards this does not mean that you should dismiss them out of hand for future problems you encounter such as this. It may the case that your current coding standards did not envisage such a scenario arising. If they did they would probably give you help as to what the alternative implementation would be.

This sounds to me like a good time to challenge your current coding standards. If the people that wrote them are still there then speak to them directly as they will either be able to answer your question as to alternative strategies or they will accept that this is a valid use-case for exceptions.

Troubadour
You may be surprised, but many platforms don't even support exceptions... so this is a legitimate question that deserves a constructive answer.
kotlinski
@kotlinski: I am saying that the non-use of exceptions should be justified. If the OP's target platform doesn't support them then that's pretty good justification! However I suspect the OP would have phrased it like that rather than say that their coding guidelines didn't allow them.
Troubadour
This sounds like a constructive answer to me. What if they don't target anything but Win32, and the original developers were old and didn't want any of this newfangled exception business that all the kids are talking about these days? Then again, you may be right, maybe not all of their target platforms support exceptions, or they have issues with throwing exceptions across dll boundaries or whatever. Talking to the people who developed the standards would definitely help explain why their standards would say this.
Sean Edwards
The first rule in any set of coding standards should be that no rule is sacrosanct (except the first rule). If good justification can be found for violating one of the rules, then violate the rule. The violation and approval of the violation by management should, of course, be documented for CYA purposes.
JeremyP
-1 "change your coding standards" is not an answer.
Justicle
@Justicle: It's just as well I didn't say that then isn't it?
Troubadour
"This sounds to me like a good time to challenge your current coding standards." Sorry - challenge, not change. :-D
Justicle
It is an answer.
DeadMG
@Justicle: Apology accepted. Now how about cancelling the downvote?
Troubadour
@Elazar: At no point did I say your company's coding standards were stupid and neither did I whine about anything. I'm confused by your hostility.
Troubadour
@Troubadour, First I apologize, I did not mean to sound hostile. I didn't mean that you whined, what I meant is, that sometimes even if something is stupid (such as the coding standard which are sometimes stupid), it's better for me to just accept the stupid thing as a fact, and find an engineering way around it, than to try to change it.The bottom line was, that I already accepted the fact that the coding standard won't be changed, and I'm more interested with the best technical way to overcome the lack of exception, and less with meta discussion about the coding standards.
Elazar Leibovich
@Elazar: Okay, no problem. It wasn't entirely clear from the original question that this was _absolutely_ not an option for you. That's fine as my answer doesn't preclude that possibility as it's only a reminder that these things can and should be queried when appropriate. In this case the query verifies that the coding standard should still be upheld. As for alternative implementations the answers given by others here have already pointed out return code variations which is what I would have said so I felt there was little point in me repeating it.
Troubadour
@Troubadour: Sorry, you didn't answer the question as asked, you gave your opinion on exceptions. The question clearly asks for an alternative (which exists, regardless of what you think about exceptions, or whether or not they can be used in the OPs situation).
Justicle
@Justicle: Yes, I did answer the question as asked. Your comment proves that you _still_ have not understood the answer. I gave no opinion on exceptions. Please re-read the answer.
Troubadour
@Troubadour: Please re-read the question. Exceptions aren't an option in this case for various reasons. The OP is asking for a technical answer, not a political one (eg change/challenge the standard). Still -1 until you propose a technical answer.
Justicle
@Justicle: The natural first step from the _original_ question was to verify that exceptions couldn't be used. My answer raised that (valid) point. We're all agreed (and have been since before your last two comments) that exceptions are not going to be used here and so this answer has successfully served its purpose. That's really the end of the story.
Troubadour
+4  A: 

However, using exception is forbidden in our coding standard (also in Google's C++ standard BTW). Is there an alternative design I can consider?

Coding standards like that are nuts.

I suggest that you ask the person / people who developed and mandated that standard how to solve your problem. If they have no good answer, use this as justification for ignoring that part of the coding standard ... with your bosses permission of course.

Stephen C
But there is a good justification! For example, Google mentions the fact that mixing exception free code with code that contains exceptions might be problematic. For example, using exceptions will force us to change compilation switches for all the project and I'm not sure it worth it. Grrr... I shouldn't have mentioned the code standard at all. It diverts the discussion from the technical stuff.
Elazar Leibovich
@Elazar - there is no justification for outright banning a construct that does things that are too difficult to get correct other in other ways. If exceptions are used properly they are just fine. The standard should focus on setting out preconditions / caveats.
Stephen C
+2  A: 

However, using exception is forbidden in our coding standard (also in Google's C++ standard BTW). Is there an alternative design I can consider?

Short answer is no.

Long answer yes :). You can make all functions return an error code (similar to the implementation of Microsoft's COM platform.

The main disadvantages of this approach are:

  • you have to handle all exceptional cases explicitly

  • your code size increases dramatically

  • the code becomes more difficult to read.

Instead of:

initialize();
while (true) {
    Message msg,out;
    recieve(msg);
    process(msg,out);
    //no global state is saved between loop iterations!
    send(out);
}

you have:

if( !succeedded( initialize() ) )
    return SOME_ERROR;

while (true) {
    Message msg,out;
    if( !succeeded( RetVal rv = recieve(msg) ) )
    {
         SomeErrorHandler(rv);
         break;
    }
    if( !succeeded( RetVal rv = process(msg,out) ) )
    {
         SomeErrorHandler(rv);
         break;
    }
    //no global state is saved between loop iterations!
    if( !succeeded( RetVal rv = send(out) ) )
    {
         SomeErrorHandler(rv);
         break;
    }
}

furthermore, the implementation all your functions will have to do the same: surround each function call with an if.

In the example above, you also have to decide if the rv value on each iteration constitutes an error for the current function and (eventually) return it directly from the while, or break the while on any error, and return the value.

In short, except for possibly using RAII in your code and templates (are you allowed to use them?), you end up close to "C code, using the C++ compiler".

Your code transforms each function from a two-liner into an eight-liner and so on. You can improve this with use of extra functions and #defined macros but macros have their own idiosyncrasies that you have to be really careful about.

In short, your coding standards are making your code unnecessarily longer, more error prone, harder to understand and more difficult to maintain.

This is a good case to present to whoever is in charge of the coding standards in your company :(

Edit: You can also implement this with signals but they are a bad replacement for exceptions: they do the same thing as exceptions, only they also disable RAII completely and make your code even less elegant and more error prone.

utnapistim
You can't make constructors return an error code: constructors have no return code.
ChrisW
No, you can't. At least not directly. You can however provide them with a return argument. This makes the code even uglier for constructors.It also disables operators overloading among other things.That is the reason I said the short answer is **no**.
utnapistim
A better option may be to avoid writing constructors that may fail: Use a separate init() function that does the beefy stuff instead.
kotlinski
True, but "ugly code is ugly" still :(
utnapistim
+2  A: 

Coding these kind of services all day long I understand your problem. Although we do have exceptions within our code, we don't return them to the external libraries that invoke it, instead we have a simple 'tribool'.

enum ReturnCode
{
  OK = 0,  // OK (there is a reason for it to be 0)
  KO,      // An error occurred, wait for next message
  FATAL    // A critical error occurred, reboot
};

I must say FATAL is... exceptional. There isn't any code path in the application that returns it, apart from the initialization (can't do much if you're not initialized properly).

C++ here brings much with RAII, since it laughs multiple paths of return off and guarantees deterministic release of the objects it holds.

For the actual code checking, you can simply use some macros:

// Here is the reason for OK being 0 and KO and Fatal being something else

#define CHECK_RETURN(Expr) if (ReturnCode code = (Expr)) return code;

#define CHECK_BREAK(Expr) if (ReturnCode code = (Expr)) \
    if (KO == code) break; else return code;

Then you can use them like so:

CHECK_RETURN( initialize() )
while(true)
{
  Message msg,out;
  CHECK_BREAK( receive(msg) )
  CHECK_BREAK( process(msg,out) )
  CHECK_BREAK( send(out) )
}

As noted, the real bummer is about constructors. You can't have "normal" constructors with such a situation.

Perhaps can you use boost::optional, if you can't, I would really suggest duplicating the functionality. Combine that with systemic factory functions in lieu of constructors and you're off to go:

boost::optional<MyObject> obj = MyObject::Build(1, 2, 3);
if (!obj) return KO;

obj->foo();

Looks much like a pointer, except that it's stack allocated and thus involves near zero overhead.

Matthieu M.
@Matthieu Thanks! That's what I was looking for! I actually thought about something in this form.My only problem is functions that returns output. It's not so nice to convert all code `if (isPolygonClockWise(poly) CHECK_RETURN(isPolygonSimple(poly, CHECK_RETURN(isPolygonClockWise(poly,
Elazar Leibovich
Remember that most functions do not throw anything, if you validate first hand (or even better, ensure that poly is always valid) then those 2 functions should never need to throw and are perfectly okay returning a boolean.
Matthieu M.
A: 

Another approach is, instead of throwing exception, set a global error indicator, and return a legal but arbitary input. Then checking in every loop iteration whether or not the global error indicator is set, and if it is - return.

If you're careful enough, you can make sure that returning legal data will never cause you to crash or to cause undefined behaviour. Thus you shouldn't care that the software will keep running a bit until it reaches to the nearest error checking condition.

For example

#define WHILE_R(cond,return_value) while (cond) {\
    if (exception_thrown) return return_value
#define ENDWHILE() }

bool isPolyLegal(Poly p) {
    PolyIter it(p);
    WHILE_R(it.next(),true) //return value is arbitary
    ...
        if (not_enough_memory) exception_thrown = true;
    ...
    ENDWHILE()
}
Elazar Leibovich