"No return statement", but I know what it is

Suppose I have the following function:

// Precondition: foo is '0' or 'MAGIC_NUMBER_4711' // Returns: -1 if foo is '0' // 1 if foo is 'MAGIC_NUMBER_4711' int transmogrify(int foo) { if (foo == 0) { return -1; } else if (foo == MAGIC_NUMBER_4711) { return 1; } } 

The compiler complains about the "missing return statement", but I know that foo never has different values ​​than 0 or MAGIC_NUMBER_4711 , otherwise my function will not have specific semantics.

What are the preferred solutions for this? This is really a problem, i.e. What does the standard say?

+3
c ++
Mar 05 2018-12-12T00:
source share
4 answers

Sometimes your compiler cannot deduce that your function actually has no missing return. In such cases, there are several solutions:

Suppose the following simplified code (although modern compilers will see that there is no path leak, just an example):

 if (foo == 0) { return bar; } else { return frob; } 

Change code structure

 if (foo == 0) { return bar; } return frob; 

This works well if you can interpret the if statement as a kind of firewall or prerequisite.

interruptions ()

 if (foo == 0) { return bar; } else { return frob; } abort(); return -1; // unreachable 

Return something else accordingly. The commentary tells about the programmers and themselves, why this is.

quit

 #include <stdexcept> if (foo == 0) { return bar; } else { return frob; } throw std::runtime_error ("impossible"); 

Disadvantages of a single exit exit point

control flow

Some return to the one-inverse-function-function aka with one function-exit point as a workaround. This can be considered deprecated in C ++ because you almost never know where the function will actually exit:

 void foo(int&); int bar () { int ret = -1; foo (ret); return ret; } 

It looks good and looks like SFEP, but reverse engineering a third-party proprietary libfoo shows:

 void foo (int &) { if (rand()%2) throw ":P"; } 

This argument is not valid if bar() nothrow and therefore can only call nothrow functions.

complexity

Each volatile variable increases the complexity of your code and increases the brain load of your supporting code. This means that more code and more states to check and verify, in turn, means that you suck out more states from the brains of the maintenance staff, which in turn means that less guardian brain power remains for important material.

missing default constructor

Some classes do not have a default, and you will have to write really dummy code, if at all possible:

 File mogrify() { File f ("/dev/random"); // need bogus init because it requires readable stream ... } 

It’s hack enough to declare it.

+9
Mar 05 2018-12-12T00:
source share

On C89 and C99, a return statement is never required. Even if it is a function with a return other than void .

C99 only says:

(C99, 6.9.1p12 "If the function that completes the function is reached and the function call value is used by the caller, the behavior is undefined."

In C ++ 11, the Standard says:

(C ++ 11, 6.6.3p2) "Turning off the end of a function is equivalent to returning without a value, which leads to undefined behavior in a function returning a value"

+2
Mar 05 2018-12-12T00:
source share

Just because you can say that the input will have only one of two values, this does not mean that the compiler can, so he expected it to generate such a warning.

You have several options to help the compiler understand this.

  • You can use an enumerated type for which two values ​​are the only valid enumerated values. Then the compiler can immediately say that one of the two branches should be executed, and there is no missing return.

  • You can abort at the end of the function.

  • You could throw an appropriate exception at the end of the function.

Note that the last two options are better than suppressing the warning, because it predictably shows you when the prepositions are violated, rather than allowing undefined behavior. Since a function accepts an int , not a class type or an enumerable, it is only a matter of time before someone calls it a value other than two valid values, and you want to catch them sooner in the development stage than pushing them off as undefined behavior, since it violates function requirements.

+2
Mar 05 '12 at 18:39
source share

Actually, the compiler does exactly what it should.

 int transmogrify(int foo) { if (foo == 0) { return -1; } else if (foo == MAGIC_NUMBER_4711) { return 1; } // you know you shouldn't get here, but the compiler has // NO WAY of knowing that. In addition, you are putting // great potential for the caller to create a nice bug. // Why don't you catch the error using an ELSE clause? else { error( "transmorgify had invalid value %d", foo ) ; return 0 ; } } 
0
May 28 '12 at 11:55
source share



All Articles