我可以让C ++编译器决定是按值传递还是按引用传递?

时间:2012-11-16 00:06:40

标签: c++ performance compiler-construction pass-by-value pass-by-const-reference

看看这个假设的头文件:

template <class T>
class HungryHippo {
public:
    void ingest(const T& object);
private:
    ...
}

现在,对于HungryHippo<string>来说,你想要ingest对字符串的引用是有意义的 - 复制字符串可能非常昂贵!但是对于HungryHippo<int>而言,它的含义却不那么明显。直接传递int可能非常便宜(大多数编译器会在寄存器中执行),但是传递对int的引用是一个额外的不必要的间接级别。这一切都适用于返回值。

有没有办法向编译器建议“嘿,我不打算修改参数,所以决定是通过值还是通过引用来传递,这取决于你的想法是什么更好“?

可能相关的一些事情:

  • 我可以通过编写template <class T, bool PassByValue> class HungryHippo手动伪造此效果,然后专注于PassByValue。如果我想得到真正的幻想,我甚至可以根据PassByValuesizeof(T)来推断std::is_trivially_copyable<T>。无论哪种方式,当实现看起来几乎相同时,这是一项额外的工作,我怀疑编译器可以更好地决定是否通过值传递。
  • libc++项目似乎通过内联很多函数来解决这个问题,因此编译器可以选择一级,但在这种情况下,让我们说ingest的实现是公平的复杂且不值得内联。正如评论中所解释的,默认情况下所有模板函数都是inline

2 个答案:

答案 0 :(得分:8)

boost::call_traits标题正好处理此问题。请查看here

具体而言,call_traits<T>::param_type选项包括以下说明:

  

如果T是小型内置类型或指针,则定义param_type   作为T const,而不是T const&。这可以提高能力   编译器,如果它们依赖,则优化函数体中的循环   在传递的参数上,传递参数的语义是   否则不变(需要部分专业化)。

在您的情况下,您可以按如下方式定义ingest

template <class T>
class HungryHippo {
public:
    void ingest(call_traits<T>::param_type object);
    // "object" will be passed-by-value for small 
    // built-in types, but passed as a const reference 
    // otherwise
private:
    ...
};

这实际上是否会对您的实际代码/编译器组合产生很大影响,我不确定。一如既往,你必须运行一些实际的基准测试,看看会发生什么......

答案 1 :(得分:0)

虽然诸如boost提到的call_traits<T>之类的技巧做了他们声称在这种情况下做的事情,但我认为你假设编译器在最重要的情况下还没有进行这种优化。毕竟,这是微不足道的。如果接受const T&sizeof(T) <= sizeof(void*),则由C ++引用语义强加的不变量允许编译器在整个函数体中简单地替换该值,如果它是胜利的话。如果不是这样,那么最糟糕的开销是函数序言中的一个指向arg的引用。