I have some code that looks like this:
static std::string Foo(const std::string& blah)
{
if ( someWierdEdgeCase() ){
return false; // <-- this line has a compiler error
}
std::string resourcePath;
resourcePath.append("/assets/");
return resourcePath;
}
It used to compile fine, but then I upgraded to Xcode 5.1, and now it no longer compiles. The error I get is the following one:
No viable conversion from 'bool' to 'std::string'
I would like to know what I should replace 'return false' with so that this works the way it used to.
Normally, I would be happy to return something other than false, and clearly that is not good behavior. But somehow this code used to compile and run, and I want to understand what it was doing, in case some other part of this codebase is relying on what is certainly weird behavior.
This:
return false; // <-- this line has a compiler error
There is no standard way to convert bool to std::string (please correct me if there is or was something special in gcc (the old XCode mac compiler)). This means that your code base used to contain explicit code to convert the bool to string.
If it is not compiling now this suggests this conversion was removed from your code base.
A couple of people of suggested alternatives. But I doubt any of these are going to work. As the old code had a depedency on how it used to work. So making any specific recomendation will depend on working out how the old code compiled and what it returned when someWierdEdgeCase() is true. Basically you need to replicate this behavior.
Otherwise you need to hunt down all used cases in your code and change the behavior to match the new behavior. In this case I would change the name of the function. Re-Compile and see where the code breaks and check the behavior at each location and make sure it behaves the same.
static std::string Foo(const std::string& blah)
{
std::string resourcePath = "";
if ( someWierdEdgeCase() ){
return resourcePath; // <-- Now you're returning a string
}
resourcePath.append("/assets/");
return resourcePath;
}
If you need the return type to be - for whatever reason - not always present, return by pointer, instead of returning by value.
static yourType* Foo(const std::string& blah){
if ( someWierdEdgeCase() ){
return 0;
}
}
Then you can test and assign the function in the same line
yourType* result;
if(result = Foo("something")){
// the result was correct
Of course - since your function returns a std::string, you can return an empty string (""), or - also independent of the return type - throw an exception.
I had same issue that with the fact that my interface file and implementation file were using different data types in method declaration.Putting same data type on both place in method declaration error went away.
Related
I often use -1 as the invalid value type when returning from a function, where the input yields incorrect output. For instance, writing an indexing function where the index is out of bounds, instead of throwing an exception, -1 can be returned. But when writing a function that has negative values as possible return types, this technique does not work. What is the correct way to return an invalid type value in such instances?
The technique I use mostly is to set the return type to be of type *int, and return a Pointer to NULL. But, that requires all return values to be of a pointer type, which seems like an extra overhead to the function. Is there an accepted standard for returning values in such cases?
In newer C++, I'd suggest using std::optional<>; if you don't yet have it, boost::optional<>.
One option would be to let your function take a bool& as an output parameter used to indicate if the returned value is valid.
int myFunc(bool& valid); // sets 'valid' to true if result is usable, false otherwise
Users can then do
bool valid = false;
Int result = myFunc(valid);
if (!valid) {
// Handle error
}
// Use result
Not the most pretty solution, but it does the job.
Apart from the answer I provided above, there's a very clean, continuation-passing solution (given you're non-virtual):
template<typename Success, typename Failed>
void parse( const std::string& str, Success s, Failed f )
{
auto a = start_parse(str);
if( a.problem() )
return f(); // you _might_ have an error code here
s( finish_parse(str, a) );
}
Then you might customize by:
Success:
[&i] (int i_) { i = i_; }
out(i), where out(int& output_) returns the above lambda for output_
actual code doing something useful
function to continue with
Failed:
[&i]{ i = 0; }, `[&i]{ i = nullopt; }, or any other default value
[] { throw MyFavouriteException(); }
retry logic
std::terminate()
[]{} if you don't care (or if you're 100% sure it'll succeed)
It might look a little verbose, but IMHO:
it's trivial to read
any other schematics can be mimicked, even if there's no default c'tor
easy to change as well
'you don't pay for what you don't use', can surely be optimized away
every schematic is visible and apparent from code:
for default value, caller sets it, not callee or global
std::optional<> and default value are handled the same
for exception, caller knows better what to throw
for no action, you don't have to lookup the implementation to know this
for std::terminate(), well, you know what to expect
if you 'speak' CPS, you might actually continue and save an if / catch / etc.
The only issue I see is constructor initializer lists. Any thoughts on this?
I still shocked after detecting a mysterious issue on our project.
We realized that calling HasMember("string") was performing an extra seek. So, for performance reasons, we change it.
The main idea is:
Instead of calling HasMember and afterwards precaching the reference like:
rapidjson::Document d;
d.Parse<0>(json);
if(d.HasMember("foo"))
{
const rapidjson::Value& fooValue = d["foo"];
// do something with fooValue
}
Changed to:
rapidjson::Document d;
d.Parse<0>(json);
const rapidjson::Value& fooValue = d["foo"];
if( !fooValue.IsNull() )
{
// do something with fooValue
}
This was pretty good, we save to perform two seeks instead of only one. However, here it comes the issue.
If you start looking how rapidjson implements nullvalue (returned by default when seek fails) you will see the following code:
//! Get the value associated with the object's name.
GenericValue & operator[](const Ch* name) {
// Check
if (Member * member = FindMember(name)) {
return member->value;
} else {
// Nothing
static GenericValue NullValue;
return NullValue;
}
}
// Finder
const GenericValue & operator[] (const Ch* name) const {
// Return
return const_cast<GenericValue &> (* this)[name];
}
So, if didn't find the member we return a local static variable. This may sound good enough at first glance but since this is returning by reference can lead easily to hidden bugs.
Imagine that someone change the reference of the static NullValue. This will cause that all further calls to IsNull (after looking for it) will fail because the NullValue changed to another type or even to random memory.
So, what do you thing? Do you think this is a good null pattern example?
I am confused, I like the idea of returning a default null value but since is not returned as const this is dangerous. And, even, if we do return it in all cases as const, devs can still use const_cast (but I wouldn't expect that, if they do, will be under them responsibility).
I want to hear other cases and examples like this one. And if someone can give a real solution under rapidjson code would be basically awesome and amazing.
The pitfall of this design has been raised up by the community long time ago. Since operator[] also needs a non-const version, it is not possible to maintain the integrity of the static variable.
So this API has been changed in newer versions of RapidJSON. The operator[] simply assert for non-exist key. If it is unsure that a key is exist, it is preferably using
MemberIterator FindMember(const Ch* name);
ConstMemberIterator FindMember(const Ch* name) const;
And comparing the value with MemberEnd() to check whether the key exists. This is also documented here.
Besides, please note that RapidJSON has been moved to GitHub. Many issues has been resolved. Please use the newest version if possible. Thank you.
P.S. I am the author of RapidJSON.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
The short version of this question is how to implement a single function that return both true and false while providing details upon failure (false)?
Say I want to create static function remove() that will get a path as a string and remove it from the file system.
Assuming remove operation may cause some unexpected errors, I'd like to be able to return a status.
Version 1
static bool remove( const string& path );
This will return true if path was removed and false otherwise.
But what if I need more details regarding the failure of the remove process?
Version 2
static void remove( const string& path );
This function now throw some exception on failure which will basically return the reason why remove process failed. This mandates each caller to use try-catch when calling this function which can be a bit annoying and ugly if you don't care about the result.
I trying to generate a clean signature that will allow me to combine both versions into a single one.
remove function is just one of many static utility functions so I'd like to avoid having to leave both versions (even though they are not overrideable at the moment).
Suggestion 1:
static bool remove( const string& path, bool throw_on_fail );
Now the caller can alternate both versions of the function by passing a boolean flag.
I don't like this suggestion. As I said remove function is just one of many static utility functions. I don't think adding boolean argument for each function is such a good idea.
Suggestion 2:
static EResultCode remove( const string& path );
Here we have an enum as the result.
This one is a bit better but I can already see such bugs as the next if statement if remove("f1"). getting int value 4 from remove() does not imply success.
Suggestion 3:
static Result remove( const string& path );
Here we have a class Result that will contain both Boolean and detailed description.
This seems like an overkill to me.
Question
I looked at the API of common c++ libraries interface, wx & boost. could not find overwhelming insights there.
I'm trying to come up with a generic signature for all those functions. which way would you go?
I would definitely go with the Result class approach.
Ignoring the question of whether exceptions are the right tool to handle a file-not-found error in the first place, an additional bool parameter to enable or disable them will make client code less readable because of all the true and false arguments whose meaning is completely unclear unless the reader consults remove()'s documentation or at least its signature:
remove("file.txt", true); // what's true?!
I would also refrain from error references. It is so frustrating when you (the function's client) are forced to use additional local variables which you might not even need later on. Very C++-unlike. This approach will eventually result in a lot of client code like this:
Error dummy;
remove("file.txt", dummy);
The Result class approach means clients will have to type a bit more if they need to know the details of an error, but their code will become much clearer and readable as a result of it. Your concern that this may put an additional burden on clients seems unfounded, at least if I imagine myself as the client of remove() :)
struct status {
std::string msg;
bool success;
status(): success(true) {}
status(std::string msg_): success(false), msg(msg_) {}
explicit operator bool() const { return success; }
};
static status const success;
status func1() { return true; }
status func2() { return success; }
status func3() { return status("something went wrong); }
if (func1()) { std::cout << "success!" << std::endl; }
if (func1().success) { std::cout << "success!" << std::endl; }
auto rc = func3();
if (!rc) { std::cout << "error" << rc.msg << std::endl; }
If you have a function remove(), and that functions purpose is to remove things from the file system, we should expect it to work in the normal case.
In the case where is can't work for some reason (there are a multitude of reasons it could fail) we should treat that as an exception to the normal working case.
I would suggest:
void remove() {...}
And calling it:
try
{
remove("/home/olduser");
}
catch(std::runtime_error& e)
{
std::cerr << "Failed to remove: " << e.what() << '\n';
}
Exceptions are part of the language for a reason, use them.
You said you looked to boost (and others) for inspiration. Look at the implementation of boost::asio. Almost all of the functions there have two overloads, one that takes an error code to report into, and one that has the same behavior but simply throws the error code as an exception in the case of failure.
Providing both may be overkill. My preference is to rely on exception handling, as it was specifically designed for handling these types of situations.
What I did in one case is have the function return a char
const*, with a nullptr for success, and the error message for
failure. Still, in this case, the functions were extern "C",
so I didn't have nearly as many alternatives. In C++, I'd
probably define a class, and return it. The class could have an
implicit conversion to bool if you wanted, but I'm not
convinced that it's a good idea; I'd have a succeeded function
which returned bool: it's a lot clearer.
Note that even in this case, you'll have to store the return
value into a local variable, in order to have the additional
information still present after you've detected the failure; you
cannot simply write:
if ( remove( path ) ) {
// error
} else {
// success
}
but need to write:
Results results = remove( path );
if ( !results ) {
// error, do something with results.message()
} else {
// success
}
Also rather painful, almost as much as a try catch.
You can use something like
static bool remove( const string& path, tStatus& myStatus );
And define tStatus as whatever type you want to return errors as. Could be as simple as typedef int tStatus;
You may use:
static bool remove(const string& path, std::nothrow_t);
static void remove(const string& path);
You could also let the function return a bool, and among the parameters you pass a reference to a structure that may contain the reason. Like this:
bool remove(const string& path, FailReason* fr){
//if the FailReason is a null pointer we don't fill it
If(fr != 0);
}
You can pass null in the fail struct
I am working in C++ with two large pieces of code, one done in "C style" and one in "C++ style".
The C-type code has functions that return const char* and the C++ code has in numerous places things like
const char* somecstylefunction();
...
std::string imacppstring = somecstylefunction();
where it is constructing the string from a const char* returned by the C style code.
This worked until the C style code changed and started returning NULL pointers sometimes. This of course causes seg faults.
There is a lot of code around and so I would like to most parsimonious way fix to this problem. The expected behavior is that imacppstring would be the empty string in this case. Is there a nice, slick solution to this?
Update
The const char* returned by these functions are always pointers to static strings. They were used mostly to pass informative messages (destined for logging most likely) about any unexpected behavior in the function. It was decided that having these return NULL on "nothing to report" was nice, because then you could use the return value as a conditional, i.e.
if (somecstylefunction()) do_something;
whereas before the functions returned the static string "";
Whether this was a good idea, I'm not going to touch this code and it's not up to me anyway.
What I wanted to avoid was tracking down every string initialization to add a wrapper function.
Probably the best thing to do is to fix the C library functions to their pre-breaking change behavior. but maybe you don't have control over that library.
The second thing to consider is to change all the instances where you're depending on the C lib functions returning an empty string to use a wrapper function that'll 'fix up' the NULL pointers:
const char* nullToEmpty( char const* s)
{
return (s ? s : "");
}
So now
std::string imacppstring = somecstylefunction();
might look like:
std::string imacppstring( nullToEmpty( somecstylefunction());
If that's unacceptable (it might be a lot of busy work, but it should be a one-time mechanical change), you could implement a 'parallel' library that has the same names as the C lib you're currently using, with those functions simply calling the original C lib functions and fixing the NULL pointers as appropriate. You'd need to play some tricky games with headers, the linker, and/or C++ namespaces to get this to work, and this has a huge potential for causing confusion down the road, so I'd think hard before going down that road.
But something like the following might get you started:
// .h file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction();
}
// .cpp file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction() {
const char* p = ::somecstylefunction();
return (p ? p : "");
}
}
Now you just have to add that header to the .cpp files that are currently calling calling the C lib functions (and probably remove the header for the C lib) and add a
using namespace clib_fixer;
to the .cpp file using those functions.
That might not be too bad. Maybe.
Well, without changing every place where a C++ std::string is initialized directly from a C function call (to add the null-pointer check), the only solution would be to prohibit your C functions from returning null pointers.
In GCC compiler, you can use a compiler extension "Conditionals with Omitted Operands" to create a wrapper macro for your C function
#define somecstylefunction() (somecstylefunction() ? : "")
but in general case I would advise against that.
I suppose you could just add a wrapper function which tests for NULL, and returns an empty std::string. But more importantly, why are your C functions now returning NULL? What does a NULL pointer indicate? If it indicates a serious error, you might want your wrapper function to throw an exception.
Or to be safe, you could just check for NULL, handle the NULL case, and only then construct an std::string.
const char* s = somecstylefunction();
if (!s) explode();
std::string str(s);
For a portable solution:
(a) define your own string type. The biggest part is a search and replace over the entire project - that can be simple if it's always std::string, or big one-time pain. (I'd make the sole requriement that it's Liskov-substitutable for a std::string, but also constructs an empty string from an null char *.
The easiest implementation is inheriting publicly from std::string. Even though that's frowned upon (for understandable reasons), it would be ok in this case, and also help with 3rd party libraries expecting a std::string, as well as debug tools. Alternatively, aggegate and forward - yuck.
(b) #define std::string to be your own string type. Risky, not recommended. I wouldn't do it unless I knew the codebases involved very well and saves you tons of work (and I'd add some disclaimers to protect the remains of my reputation ;))
(c) I've worked around a few such cases by re-#define'ing the offensive type to some utility class only for the purpose of the include (so the #define is much more limited in scope). However, I have no idea how to do that for a char *.
(d) Write an import wrapper. If the C library headers have a rather regular layout, and/or you know someone who has some experience parsing C++ code, you might be able to generate a "wrapper header".
(e) ask the library owner to make the "Null string" value configurable at least at compile time. (An acceptable request since switching to 0 can break compatibility as well in other scenarios) You might even offer to submit the change yourself if that's less work for you!
You could wrap all your calls to C-stlye functions in something like this...
std::string makeCppString(const char* cStr)
{
return cStr ? std::string(cStr) : std::string("");
}
Then wherever you have:
std::string imacppstring = somecstylefunction();
replace it with:
std::string imacppstring = makeCppString( somecystylefunction() );
Of course, this assumes that constructing an empty string is acceptable behavior when your function returns NULL.
I don't generally advocate subclassing standard containers, but in this case it might work.
class mystring : public std::string
{
// ... appropriate constructors are an exercise left to the reader
mystring & operator=(const char * right)
{
if (right == NULL)
{
clear();
}
else
{
std::string::operator=(right); // I think this works, didn't check it...
}
return *this;
}
};
Something like this should fix your problem.
const char *cString;
std::string imacppstring;
cString = somecstylefunction();
if (cString == NULL) {
imacppstring = "";
} else {
imacppstring = cString;
}
If you want, you could stick the error checking logic in its own function. You'd have to put this code block in fewer places, then.
I was trying to answer this question. As suggested by the accepted answer, the problem with that code is that not all control paths are returning a value. I tried this code on the VC9 compiler and it gave me a warning about the same. My question is why is just a warning and not an error? Also, in case the path which doesn't return a value gets executed, what will be returned by the function (It has to return something) ? Is it just whatever is there on top of the stack or is the dreaded undefined behavior again?
Failing to return a value from a function that has a non-void return type results in undefined behaviour, but is not a semantic error.
The reason for this, as far as I can determine, is largely historical.
C originally didn't have void and implicit int meant that most functions returned an int unless explicitly declared to return something else even if there was no intention to use the return value.
This means that a lot of functions returned an int but without explicitly setting a return value, but that was OK becase the callers would never use the return value for these functions.
Some functions did return a value, but used the implicit int because int was a suitable return type.
This means that pre-void code had lots of functions which nominally returned int but which could be declared to return void and lots of other functions that should return an int with no clear way to tell the difference. Enforcing return on all code paths of all non-void functions at any stage would break legacy code.
There is also the argument that some code paths in a function may be unreachable but this may not be easy to determine from a simple static analysis so why enforce an unnecessary return?
I would guess it is only a warning because the compiler cannot always be 100% sure it is possible to not hit a return.
i.e. if you had:
-= source1.c =-
int func()
{
if(doSomething())
{
return 0;
}
}
-= source2.c =-
int doSomething()
{
return 1;
}
The compiler in this case might not be able to know it will always hit the return, but you do. Of course this is terrible programming practice to rely on knowing how external code works.
As for what will actually be returned it depends on the platform. On x86 ABIs EAX is used for the return value (up to 32bits) so it will return what ever was placed in that register (which could be a return from something else, a temporary value or total garbage).
Technically it is not guaranteed to be an error if you call a function and that function always throws an exception. For example here is some pseudo code, and you know raiseError always throws.
MyClass func( params )
{
if( allIsValid() )
{
return myObject;
}
else
{
raiseError( errorInfo );
}
}
If the compiler cannot see the implementation of raiseError, it will not know that the function is going to throw. So really there is actually no undefined behaviour here. Of course it is good to silence the compiler here, which you can do with either writing a "dummy" return statement after raiseError, or a dummy "throw". I call them "dummy" because they will never be reached in reality. (You can also suppress the warning if you really insist). However there is no error or undefined behaviour.
here is another reason it isn't an error
the following will give you the same warning since the compiler expects you to return something from the catch block even though you're throwing there
int foo(){
try{
return bar(0);
} catch(std::exception& ex){
//do cleanup
throw ex;
}
}
int bar(unsigned int i){
if(i == 0){
throw std::string("Value must be greater than 0");
} else{
return 0;
}
}
Another example where it may be okay for some control paths to not return a value:
enum E : int {A, B};
int foo(E e) {
switch (e) {
case A: return 30;
case B: return 50;
}
}
It's possible that e won't be A or B, but the implication is that it always will be one of those values. If that's the case then the code is fine and there's no problem. Making this warning into a mandatory error would require unnecessary, 'unreachable' clutter.
If you want the warning to be an error anyway, you can configure your compiler to do that with a flag like /WX or -Werror. Though of course you should note that different compilers may make different determinations as to what's unreachable so you may be fixing different things for different compilers.
It is not an error because it may be the intended behaviour. For example, some encryption libraries use uninitialized local data as a step for seeding. As return values are kept in calling-convention and platform specific locations, this may help in some unusual (like the above) situations. In this case, the function returns whatever is left on the register used to return the return value.
Consider the following scenario:
UINT GenderID(GENDER gender)
{
switch(gender)
{
case MALE:
return MALE_ID;
case FEMALE:
return FEMALE_ID;
}
// default not required because [GENDER] in our 'Matrix' CAN be either M or F
}
a C++ complier should let you have your 'Matrix' your way; Thus its not an Error.