Reputation: 9605
In the following two versions of switch case, I am wondering which version is efficient.
1:
string* convertToString(int i)
{
switch(i)
{
case 1:
return new string("one");
case 2:
return new string("two");
case 3:
return new string("three");
.
.
default:
return new string("error");
}
}
2:
string* convertToString(int i)
{
string *intAsString;
switch(i)
{
case 1:
intAsString = new string("one");
break;
case 2:
intAsString = new string("two");
break;
case 3:
intAsString = new string("three");
break;
.
.
default:
intAsString = new string("error");
break;
}
return intAsString;
}
1: has multiple return statements will it cause compiler to generate extra code?
Upvotes: 3
Views: 2861
Reputation: 783
The funny part is you worry about efficieny of break then return but make a new string every time.
The answer is it's up to the compiler, but it should not matter either way. Avoiding the new string will if you call this all the time.
The switch can often be optimized so that it performs a jump instead of a bunch of if else, but if you look in the assembly source you'll generally be underwhelmed by how little the optimizer does.
Upvotes: 0
Reputation: 20496
There should not be any measurable difference, return statements should not generate any machinery. They should put a pointer to the string object (allocated on the heap) on the stack of the callsite.
Upvotes: 0
Reputation: 279395
You optimise[*] switch statements by doing as little work as possible in the switch (because it's uncertain whether the compiler will common up the duplication). If you insist on returning a string by pointer, and using a switch statement, I'd write this:
string *convertToString(int i) {
const char *str;
switch(i) {
case 1 : str = "one"; break;
// etc
default : str = "error"; break;
}
return new string(str);
}
But of course for this example I'd probably just use a lookup table:
const char *values[] = {"error", "one", ... };
string convertToString(unsigned int i) {
if (i >= sizeof(values)/sizeof(*values)) i = 0;
return values[i];
}
That said, I just answered a question about the static initialization order fiasco, so you don't in general want rules of thumb which demand globals. What you do has to depend on the context of the function.
[*] Where I mean the kind of rule-of-thumb optimisation that you do when writing portable code, or in your first version, in the hope of creating code that is clear to read and won't need too much real optimisation. Real optimisation involves real measurements.
Upvotes: 1
Reputation: 10128
You can never know how optimization will influence the code produced unless you compile with a specific compiler version, a specific set of settings and a specific code base.
C++ optimizing compilers may decide to turn your source code upside down to gain a specific optimization only available for compiler architecture so-and-so without you ever knowing it. A powerful optimizing compiler may e.g. find out that only 2 out of 10 cases are ever needed and will optimize away the whole switch-case-statement.
So my answer to your question is: Mu.
Upvotes: 3
Reputation: 4950
Consider keeping the strings as static constants:
static char const g_aaczNUMBER[][] =
{
{"Zero"}, { "One" }, ...
};
static char const g_aczERROR[] = { "Error" };
char* convertIntToString(int i) const {
return i<0 || 9<i ? g_aczERROR : g_aaczNUMBER[i];
}
Upvotes: 1
Reputation: 22493
There should be no difference in the compiled code. However:
Upvotes: 6
Reputation: 400109
This is a premature optimization worry.
The former form is clearer and has fewer source lines, that is a compelling reason to chose it (in my opinion), of course.
You should (as usual) profile your program to determine if this function is even on the "hot list" for optimization. This will tell you if there is a performance penalty for using break
.
As was pointed out in the comments, it's very possible that the main performance culprit of this code is the dynamically allocated strings. Generally, when implementing this kind of "integer to string" mapping function, you should return string constants.
Upvotes: 29
Reputation: 46051
A switch statement is basically a series of if
statements as generated machine instructions. One simple optimization strategy is to place the most frequent case
first in the switch statement.
I also recommend the same solution as Sebastian but without the assert.
static const char *numberAsString[] = {
"Zero",
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
};
const char *ConvertToString(int num) {
if (num < 1 || num >= (sizeof(numberAsString)/sizeof(char*)))
return "error";
return numberAsString[num];
}
Upvotes: 3
Reputation: 41027
I would suggest something of the form:
void CScope::ToStr( int i, std::string& strOutput )
{
switch( i )
{
case 1:
strOutput = "Some text involving the number 1";
... etc etc
}
By returning a pointer to a string created on the heap, you risk memory leaks. Specifically regarding your question, I would suggest that the least number of return paths is more advisable than premature optimisation.
Upvotes: 1
Reputation: 44652
There won't be any difference in efficiency here. Certainly none that will matter. The only benefit of going with option #2 is if you'll need to do some post-processing of the string that applies to all cases.
Upvotes: 0
Reputation: 4240
They will almost certainly both be compiled to an identical, highly-efficient branch table. Use whichever one you feel is clearer.
Upvotes: 1
Reputation: 22644
Both are.
What you should really be concerned about is your use of pointers here. Is it necessary? Who will delete these strings? Isn't there a simpler alternative?
Upvotes: 9
Reputation: 30449
If you turn optimizing on, both functions will very likely generate equivalent code.
Upvotes: 2
Reputation: 229874
The compiler most probably will optimize both versions to the same code.
Upvotes: 1