将原始类型的常量引用作为函数参数传递

8
请查看以下函数:

考虑以下函数:

template <class T, class Priority>
void MutableQueue<T, Priority>::update(const T& item, const Priority& priority)
{
   ...
}

现代的x86-64编译器是否足够聪明,如果优先级类型可以适应寄存器,会通过值而不是引用传递优先级参数呢?

1
我确实这么认为。但是,如果实现暴露给外部模块,它必须满足ABI要求 - 在这种情况下,引用就是引用。一般来说,你应该避免对基本类型使用引用 - 有方法可以做到这一点。 - davmac
1
我的猜测是,如果类型为 T 的实例可以适应寄存器,则编译器将通过复制进行传递。否则它可能会通过指针传递变量。 - Thomas Matthews
1
我使用clang编译器进行了简单的测试。看起来编译器确实进行了优化。它基本上生成了一个经过优化的版本(例如内联函数或按值传递),以及一个符合ABI要求但可能未被使用且只是存在于代码中的版本。 - Jansen du Plessis
3个回答

3
如@black所提到的,优化是与编译器和平台相关的。也就是说,当我们使用一个好的优化编译器时,通常会期望发生许多优化。例如,我们指望函数内联、寄存器分配、将常量乘法和除法转换为位移等等。

回答你的问题:

如果优先级类型可以适应寄存器,现代x86-64编译器是否足够聪明,通过值而不是引用传递优先级参数?

我将简单地尝试一下。请看:

这是代码:

template<typename T>
T square(const T& num) {
   return num * num;
}

int sq(int x) {
  return square(x);
}

GCC的-O3-O2-O1可靠地执行此优化。

另一方面,Clang 3.5.1似乎不执行此优化。

你是否应该指望这种优化发生?并非总是,也不是绝对的——C++标准没有说明此类优化何时会发生。实际上,如果你使用GCC,你可以“期望”进行优化。

如果你确实希望确保进行这样的优化,你将需要使用模板特化


1
执行此替换的优化似乎是-fipa-sra。看起来clang不支持它。 - dyp

3
编译器可能会进行优化,但这不是强制性的。为了强制使用“最佳”类型,您可以使用boost:http://www.boost.org/doc/libs/1_55_0/libs/utility/call_traits.htm。将const T&(在传递值正确的情况下)替换为call_traits<T>::param_type。因此,您的代码可能会变成:
template <class T, class Priority>
void MutableQueue<T, Priority>::update(call_traits<T>::param_type item,
                                       call_traits<Priority>::param_type priority)
{
   ...
}

0

这完全取决于平台和编译器,函数参数是如何传递的也是如此。
这些细节在程序运行的系统ABI中定义;一些系统有大量寄存器,所以主要使用它们。有些将所有参数都压入堆栈,而有些混合使用到第N个参数。

同样,这是您无法依赖的事情;不过你可以通过几种方式检查它。C++语言没有寄存器的概念。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接