在以下两个版本的switch case中,我想知道哪个版本是高效的。
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:有多个return语句会导致编译器生成额外的代码吗?
答案 0 :(得分:29)
这是一个过早的优化问题。
前一种形式更清晰,源线更少,当然是选择它的一个令人信服的理由(在我看来)。
您应该(照常)对您的程序进行概要分析,以确定此功能是否在“热门列表”中进行优化。这将告诉您使用break
是否存在性能损失。
正如评论中所指出的,这个代码的主要性能元凶很可能是动态分配的字符串。通常,在实现这种“整数到字符串”映射函数时,应该返回字符串常量。
答案 1 :(得分:10)
两者都是。
你应该关注的是你在这里使用指针。有必要吗?谁会删除这些字符串?是否有更简单的替代方案?
答案 2 :(得分:6)
编译代码应该没有区别。 但是:
答案 3 :(得分:3)
除非使用特定的编译器版本,特定的设置集和特定的代码库进行编译,否则您永远不会知道优化将如何影响所生成的代码。
C ++优化编译器可能会决定颠倒您的源代码,以获得仅适用于编译器体系结构的特定优化,而您无需了解它。强大的优化编译器可以例如发现只需要10个案例中的2个,并将优化掉整个switch-case语句。
所以我对你问题的回答是:Mu。
答案 4 :(得分:3)
switch语句基本上是一系列if
语句,作为生成的机器指令。一个简单的优化策略是将最常见的case
放在switch语句中。
我也推荐与Sebastian相同的解决方案,但没有断言。
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];
}
答案 5 :(得分:2)
如果你打开优化,两个函数很可能会生成相同的代码。
答案 6 :(得分:1)
编译器很可能会将两个版本优化为相同的代码。
答案 7 :(得分:1)
他们几乎肯定都会被编译成一个相同的,高效的分支表。使用你觉得更清楚的那个。
答案 8 :(得分:1)
我会建议一些形式:
void CScope::ToStr( int i, std::string& strOutput )
{
switch( i )
{
case 1:
strOutput = "Some text involving the number 1";
... etc etc
}
通过返回指向堆上创建的字符串的指针,可能会导致内存泄漏。特别是关于你的问题,我建议最少数量的返回路径比过早优化更合适。
答案 9 :(得分:1)
考虑将字符串保持为静态常量:
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];
}
答案 10 :(得分:1)
通过在交换机中尽可能少地工作来优化[*] switch语句(因为不确定编译器是否会共享复制)。如果你坚持用指针返回一个字符串,并使用switch语句,我会写这个:
string *convertToString(int i) {
const char *str;
switch(i) {
case 1 : str = "one"; break;
// etc
default : str = "error"; break;
}
return new string(str);
}
但是当然对于这个例子我可能只是使用查找表:
const char *values[] = {"error", "one", ... };
string convertToString(unsigned int i) {
if (i >= sizeof(values)/sizeof(*values)) i = 0;
return values[i];
}
那就是说,我刚回答了一个关于静态初始化顺序惨败的问题,所以你通常不需要经验法则来求全局变量。你所做的事情必须依赖于函数的上下文。
[*]我指的是在编写可移植代码时或在第一版中执行的经验法则优化,希望创建清晰易读且不需要太多的代码真正的优化。真正的优化涉及实际测量。
答案 11 :(得分:0)
这里的效率没有任何差别。当然没有一件事无关紧要。使用选项#2的唯一好处是,如果您需要对适用于所有情况的字符串进行一些后处理。
答案 12 :(得分:0)
不应存在任何可衡量的差异,返回语句不应生成任何机制。他们应该在调用点的堆栈上放置一个指向字符串对象(在堆上分配)的指针。
答案 13 :(得分:0)
有趣的部分是你担心休息的效率然后返回,但每次都会创建一个新的字符串。
答案取决于编译器,但无论如何都应该无关紧要。如果你一直打电话,请避免使用新字符串。
交换机通常可以进行优化,以便它执行跳转而不是一堆if if,但是如果你查看汇编源代码,那么优化器的工作量通常会让你不知所措。