Click to See Complete Forum and Search --> : Returning multiple state fields and preserving const-ness
Liche
July 16th, 2008, 05:03 AM
Say I need to return two things from a Validate function: an error code (every time, can be 'ok') and an error message (only if not ok). Exceptions are not appropriate here. At present this is done by returning the int code, and having an errorMessage_ field inside the object, which is looked at by a parent object if the validation fails. Problem is, this prevents the Validate function from being const (which it ideally would be), unless we declare errorMessage_ to be mutable (which seems inappropriate).
I can think of a few ways out of this:
1) status quo
2) pass in a non-const string reference into the validate function, which is populated if needed.
3) Declare an int + string struct, and return that.
4) Declare an ErrorState object (which we may find useful for holding other data), and return that.
2 would be ugly, 3 is simple but would add the cost of a lot of empty strings being constructed, 4 might get a bit expensive for ok states being returned from many validate functions - have a singleton 'ok' which is returned unless there is an error? Null object pattern? I guess 3 and 4 are very similar in principle.
Is there a cleverer way of doing this?
Kheun
July 16th, 2008, 05:29 AM
I like your option 4.
However, I may also take a different approach (which is a very C-style approach) by only returning the error code. When the error string is needed, I can call a translation function to retrieve the error message associated with the error code.
Liche
July 16th, 2008, 05:32 AM
The translation isn't always possible because sometimes member data are needed to populate the error string - therefore the string has to be created when the error is found.
zennehoy
July 16th, 2008, 05:49 AM
How about returning the string as the error code then? Again this is a very C-style approach (any error code return values are), but you could return a pointer to an error string on fail, 0 otherwise.
Just curious, why are exceptions not appropriate?
Cheers,
Zen
Liche
July 16th, 2008, 06:22 AM
The program parses messages and does stuff. The domain is very complex. There are a lot of ways of sending malformed messages, and a lot of ways of sending well-formed messages which are not valid due to some external state. In usage there are roughly as many messages with errors as there are without. Raising errors like this is by no means exceptional, it is expected and part of the normal operation of the system. I understood that exceptions should be saved for genuine exceptional cases - network connectivity, database error, out of memory etc. - rather than used in place of return values.
JohnW@Wessex
July 16th, 2008, 06:26 AM
unless we declare errorMessage_ to be mutable (which seems inappropriate).I don't see why. Just create a 'Get_Last_Error' const function that returns the string. And make the error string private.
Liche
July 16th, 2008, 06:35 AM
I don't see why. Just create a 'Get_Last_Error' const function that returns the string. And make the error string private.
But how can the error string be set within a const function if it isn't mutable? Returning the error isn't the problem, setting it is.
JohnW@Wessex
July 16th, 2008, 06:47 AM
I didn't see the problem in making it mutable.
exterminator
July 16th, 2008, 09:26 AM
Somehow I don't like keeping that error message or related info with your class in a mutable member. Not because of mutability but because usually the details about an error is not a part of the class' functional specifications. Imagine exception class objects being thrown on various operations with a vector being stored in the vector itself. Not nice.
So, if you don't really want to go by the route of exception, which you should. But considering you have a convincing reason, you can use std::pair<ErrorNum, ErroString> as the return type for the function. If there can be more return values, you can use a tuple - see boost tuple library.
Liche
July 17th, 2008, 04:04 AM
Thanks for your input. I've experimented with a Result object being passed-by-reference, which is working nicely - it also saves having to propagate errors up several layers:
Object::Validate(Result& _result)
{
otherObject.Validate(_result);
return;
}
OtherObject::Validate(Result& _result)
{
if(stuff)
_result.Set(error_code, "error message");
return;
}
which is a nice bonus. I'd probably have liked to use the Java-style new keyword to construct the Result where the error was raised, but this isn't desirable in C++ because it would cause the client to have to delete the Result* - given the number of uses this is asking for a memory leak. C++ can't return reference-to-locally-declared-object, and using copy constructors was unnecessarily inefficient, so this seemed the best way of approaching it.
Lindley
July 17th, 2008, 06:45 AM
The translation isn't always possible because sometimes member data are needed to populate the error string - therefore the string has to be created when the error is found.
Okay, then how about embedding the code in the string, and adding a getCode function to extract it?
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.