如果参数的所有功能都是看到它的值,那么你是否应该总是通过常量引用传递该参数?
我的一位同事表示,对于小类型来说无关紧要,但我不同意。
这样做有什么好处:
void function(char const& ch){ //<- const ref
if (ch == 'a'){
DoSomething(ch);
}
return;
}
对此:
void function(char ch){ //<- value
if (ch == 'a'){
DoSomething(ch);
}
return;
}
它们看起来和我的尺寸相同:
#include <iostream>
#include <cstdlib>
int main(){
char ch;
char& chref = ch;
std::cout << sizeof(ch) << std::endl; //1
std::cout << sizeof(chref) << std::endl; //1
return EXIT_SUCCESS;
}
但我不知道是否总是这样。
我相信我是对的,因为它不会产生任何额外的开销,而且它是自我记录的
但是,我想询问社区我的推理和假设是否正确?
答案 0 :(得分:3)
你的同事是对的。对于小类型(char,int),当不修改变量时,通过引用传递是没有意义的。传递值会更好,因为指针的大小(在通过引用传递的情况下使用)大约是小类型的大小。
而且,按值传递,输入的次数较少,而且可读性稍差。
答案 1 :(得分:2)
即使sizeof(chref)
与sizeof(ch)
相同,通过引用传递字符在大多数系统上也会占用更多字节:虽然标准没有说明引用实现的具体内容,但是地址(即,一个指针)经常在幕后传递。通过优化,它可能无关紧要。编写模板函数时,不应修改的未知类型的项应始终通过const引用传递。
对于小类型,您可以使用const
限定符按值传递它们,以强调您不会通过函数的签名触及参数:
void function(const char ch){ //<- value
if (ch == 'a'){
DoSomething(ch);
}
return;
}
答案 2 :(得分:2)
对于较小的值,创建引用和取消引用它的成本可能大于复制它的成本(如果存在差异)。当您考虑参考参数几乎总是作为指针实现时,尤其如此。如果您只是将值声明为const
(我仅将此值用于输入并且不会被修改),则两个文档都同样好。我通常只将const
值和所有用户定义/ STL类型的所有标准内置类型都设为const &
。
您的sizeof
示例存在缺陷,因为chref
只是ch
的别名。对于任何类型sizeof(T)
,T
都会得到相同的结果。
答案 3 :(得分:1)
尺寸不与传递相同。结果取决于ABI调用约定,但sizeof(referenceVariable)
生成sizeof(value)
。
如果函数需要的所有函数都看到它的值,那么你是否应该总是通过常量引用传递该参数?
这就是我做的事情。我知道人们不同意我,并且主张按价值传递小内置,或者更愿意省略const
。通过引用传递可以添加指令和/或消耗更多空间。我通过这种方式获得一致性,并且因为总是为任何给定平台测量传递的最佳方式是很难维护的。
除了可读性之外没有其他优势(如果这是您的偏好)。性能可能非常轻微,但在大多数情况下不会考虑。
按值传递这些小内置更常见。如果通过值传递,您可以const
限定定义(独立于声明)。
我的建议是,绝大多数团队应该只选择一种方式来传递并坚持下去,除非每条指令都重要,否则性能不应影响它。 const
永远不会伤害。
答案 4 :(得分:0)
在我看来,你通过const引用的一般方法是一个很好的做法(但请参阅下面的例子中的一些警告)。另一方面,您的朋友是正确的,对于内置类型,通过引用传递不应导致任何显着的性能提升,甚至可能导致边际性能损失。我来自C背景,所以我倾向于考虑指针的引用(即使有一些细微的差别),并且“char *”将比任何平台上的“char”更大熟悉。
[编辑:删除了错误的信息。]
在我看来,底线是当你传递更大的用户定义类型时,被调用的函数只需要读取值而不修改它们,传递“type const&amp;”是一个很好的做法。正如您所说,它是自我记录的,有助于阐明内部API的各个部分的角色。