我可以让 C++ 编译器决定是按值传递还是按引用传递?
Posted
技术标签:
【中文标题】我可以让 C++ 编译器决定是按值传递还是按引用传递?【英文标题】:Can I let the C++ compiler decide whether to pass-by-value or pass-by-reference? 【发布时间】:2012-11-04 16:42:45 【问题描述】:看看这个假设的头文件:
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
。如果我想变得非常花哨,我什至可以根据sizeof(T)
和std::is_trivially_copyable<T>
推断出PassByValue
。无论哪种方式,当实现看起来几乎相同时,这都是很多额外的工作,我怀疑编译器可以比我更好地决定是否通过值传递。
ingest
的实现相当复杂,不值得内联。 如 cmets 中所述,所有模板函数默认为 inline
。【问题讨论】:
需要考虑的一点:这听起来像是一个过早优化的好案例。您是否因为这种架构而遇到过性能问题?如果没有,你可能应该做任何语义上有意义的事情。 对于整数,通过引用传递几乎与通过值传递一样高效,因此 const 引用对这两种情况都有好处。 "在这种情况下,假设摄取的实现相当复杂,不值得内联。"在这种情况下,您别无选择。由于 HungryHippo 是模板,所以必须内联。 @Slavik81 这根本不是真的。 我想知道为什么编译器(和 ABI 规范)不只是将const int &
视为与int
相同。 (对于所有通过值传递比通过 const 引用更有效的内置类型也是如此。)它会破坏任何东西吗?
【参考方案1】:
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:
...
;
这是否真的会对您的实际代码/编译器组合产生很大影响,我不确定。与往常一样,您必须运行一些实际的基准测试,看看会发生什么......
【讨论】:
像往常一样,Boost 人已经想到了这一点。 :D 看起来简短的回答是“不,没有办法诱使编译器为你做这件事”,而长的回答是“嗯,Boost 在某些情况下设计了一种解决该问题的方法。”谢谢!【参考方案2】:虽然提到的诸如 boost 之类的技巧 call_traits<T>
在这种情况下可以做到他们声称要做的事情,但我认为您假设编译器尚未在最重要的情况下进行此优化。毕竟,这是微不足道的。如果您接受const T&
和sizeof(T) <= sizeof(void*)
,C++ 引用语义强加的不变量允许编译器简单地替换整个函数体中的值(如果它是胜利的话)。如果不是,最坏情况的开销是函数序言中的一个指向 arg 的指针取消引用。
【讨论】:
我不相信你所说的“C++ 引用语义允许编译器简单地替换整个函数体中的值”。考虑pastebin.com/xqyrQtxW ...根据您的规则,输出将为10,但根据real规则,输出为 5。您不能替换const X& 和 X。正如我在之前的评论中所说,“const”意味着你不能改变值,而不是值不能改变。 @Calvin 实际上 Matthew Hall 是对的。函数可以采用 X 而不是 const X& 但在某些特定条件下 - 例如。当您无法确定 X 的地址(它是右值)时,您仍然可以将其传递给采用 const X& 的函数,这很有效。参见示例ideone.com/6KCeve 是的,在某些情况下这种优化是合法的。然而,由于它不是总是合法的(见我的例子),你几乎不会看到编译器这样做。如果过程是内联的并且可以在内联后消除引用,则更常见的是这种情况。以上是关于我可以让 C++ 编译器决定是按值传递还是按引用传递?的主要内容,如果未能解决你的问题,请参考以下文章