假设我们有这样的代码:
template<typename T>
struct StrongValue{
constexpr const T &operator()() const {
return value;
}
T &operator()(){
return value;
}
constexpr const T &get() const {
return value;
}
T &get(){
return value;
}
T value;
};
using myint = int; // try double too
using m = StrongValue<myint>;
myint sum2(const m &a, const m &b){
return a() + b();
}
myint sum2a(const m a, const m b){
return a() + b();
}
myint sum1(myint a, myint b){
return a + b;
}
int main(){
constexpr m a{5};
constexpr m b{5};
return sum2a(a, b);
}
在clang和gcc中,-O3程序集如下所示:
sum2(StrongValue<int> const&, StrongValue<int> const&):
mov eax, DWORD PTR [rsi]
add eax, DWORD PTR [rdi]
ret
sum2a(StrongValue<int>, StrongValue<int>):
lea eax, [rdi+rsi]
ret
sum1(int, int):
lea eax, [rdi+rsi]
ret
main:
mov eax, 10
ret
为什么sum2
这样编译?
这是因为编译器会在省略引用的情况下更改函数签名,因此不允许这样做。
这是否意味着sum2
如果没有内联,则比sum2a
更昂贵?
答案 0 :(得分:1)
为什么sum2会这样编译?
这是预期的。对于sum2,您传递了两个参考。 Reference和UIApplication
是C ++的东西,CPU没有它们,对于CPU来说它们只是指针。因此,在该函数中,代码必须从内存中获取两个值并将它们求和。
另两个版本按值接收参数。
对于所有3个版本,编译器都选择使用UIApplication
调用约定,这就是为什么在const
和__regcall
寄存器中传递两个参数的原因。这就是其他两个版本仅用一条指令即可计算结果的方式。
这是否意味着,如果未内联,sum2比sum2a昂贵吗?
通常,是的。您不应通过const引用传递整数,而应通过值传递整数。但是,确切的性能影响可以忽略不计,唯一的发现方法是分析。
答案 1 :(得分:0)
不同之处在于,sum2
的参数本质上是指针,而sum2a
的参数是值。这意味着必须在sum2
中取消对指针的引用才能获取可以添加的实际值,而在sum2a
中可以立即添加值。
过度使用常量引用是一个常见错误。对于廉价复制的对象,通常最好按值传递参数。