Frank Frank - 21 days ago 5
C++ Question

Multiple return statements and performance in C++

In terms of performance, is there any reason to favour a single return statement over multiple within a function?

Consider the trivial examples below.

int min(int a, int b)
{
if (a < b)
return a;

return b;
}

int min2(int a, int b)
{
int result;

if (a < b)
result = a;
else
result = b;

return result;
}

enum class Fruit { Apple, Orange, Banana };
std::string fruitToString(Fruit f)
{
switch (f)
{
case Fruit::Apple:
return "Apple";
case Fruit::Orange:
return "Orange";
case Fruit::Banana:
return "Banana";
default:
return "Unknown Fruit";
}
}

std::string fruitToString2(Fruit f)
{
std::string result;

switch (f)
{
case Fruit::Apple:
result = "Apple";
break;
case Fruit::Orange:
result = "Orange";
break;
case Fruit::Banana:
result = "Banana";
break;
default:
result = "Unknown Fruit";
}

return result;
}


Note that I realise that opinion is divided in terms of style, so I would like answers to focus on the performance aspect.

Answer

Return or not to return, that is the question. Is it ?

For the first snippet, an optimizer may well generate the same code for both alternatives. For GCC 6.2 for example (see online compiler):

    cmp     edi, esi
    mov     eax, esi
    cmovle  eax, edi
    ret

And by the way, it will still be the same assembler code for:

int min3(int a, int b)
{
    return a < b? a:b;
}

Here, the performance is more related to the statistic distribution of the values: if a is 99% the largest, then reverting b and a could be a couple of nanoseconds faster: because there will be one less move in most of the case. But for most applications values are not so predictable, and the performance difference so tiny that it will never be noticed.

The switch example

For the switch, there are chances that the compiler uses a branch table if there are enough values to justify the small initial overhead. With very large list of values, a map will certainly provide better results using a binary search on the key.

Nevertheless here it produces a sequence of comparisons, and again, the order of the values in the switch (e.g. the most frequent first) can influence performance more than the return approach.

If you try your snippet on godbolt, you'll find out that the direct return will produce smaller and apparently faster code. This seems due to the string type that make life of the optimizer more difficult. But I'd not bet on such situation in the more general case (for example, using const char* results again in the same code for both functions)

Quote of the day:

Premature optimization is the root of all evil - Donald Knuth