问题 内联函数参数传递


有需要吗? 性能 - 为... 一致 函数传递其参数 const参考 喜欢

foo(const T & a, const T &b)

与价值相比

foo(T a, T b)

如果我不改变函数中a和b的值? C ++ 11是否会改变推荐的具体内容?


2316
2017-10-02 13:32


起源

值是值,引用是引用。在意义上传递一个const引用而不是传递一个值是一个错误,可以咬回来。看到 stackoverflow.com/questions/4705593/int-vs-const-int/... - 6502
@ 6502:这是使用引用使逻辑更复杂的一个很好的例子(v.push_back(v[0])是合法的,因为标准库必须包含额外的逻辑)。 - Ben Voigt
@BenVoigt:很高兴看到此请求已添加到标准中。它在哪里陈述? - 6502
@ 6502:如果引用有效时 push_back 被称为标准库的责任是用它做正确的事情。 - Ben Voigt
@BenVoigt:对不起,我不同意。当调用传递引用的函数时,如果引用的对象在函数持续时间内没有足够长的时间,那么它就是调用者问题(被调用者无法控制它)。 AFAIK标准并没有说复制操作必须在解除分配之前完成:如果一个实现想要这样做,那么一个有效的C ++编译器可以使守护进程从我的鼻子中移开仍然保持合规。顺便说一下,现在使用C ++ 0x更复杂的东西...可以重新分配使用移动构造函数吗?如果这样只是推迟旧存储的破坏是不够的...... - 6502


答案:


如果参数是临时的,则按值传递只能忽略复制构造函数调用。

在内联函数时,通过const引用传递基本类型将不会产生任何成本。但是按值传递复数左值将强加一个可能很昂贵的复制构造函数调用。所以更喜欢传递const引用(如果别名不是问题)。


11
2017-10-02 16:47



除了别名问题之外,还存在终身问题。 - 6502
@ 6502:肯定是在返回值上。对于参数,可能会出现寿命问题,但它们非常罕见。而且无论如何我会认为它们是别名问题的一个子集。 - Ben Voigt
@BenVoigt Passing primitive types by const reference will have no cost when the function is inlined. 你是说,“在成本方面没有任何好处”?你能否确认是否有什么可以通过的 const int& 或者a const int 当函数内联时? - Antonio
@Antonio:不,我的意思是我说的。一般来说,路过的成本很高 const reference:被调用者除了实际数据外还必须访问指针,这意味着内存访问的两倍。被调用者还必须担心别名,这会抑制几个优化。当内联函数时,编译器可以确定是否实际上存在别名,并且通常可以执行这些优化并直接访问数据,而不是通过额外的指针。 - Ben Voigt


从理论上讲,没有引用的那些可能会被复制到内存中,因为你的内联函数可能会修改它们(即使它实际上没有)。

在许多情况下,编译器足够聪明,可以选择那种东西,但它取决于编译器和优化设置。此外,如果您的函数调用类变量中的任何非const成员函数,那么您的编译器必须足够聪明,以检查它们是否也在修改任何内容。

通过使用const引用,您基本上可以给它一个相当清楚的指示。

编辑:我只是看一下简单的机器代码 测试程序 在ddd中用GCC 4.6编译。生成的代码似乎相同,所以它似乎已经优化了。对于其他编译器来说,这仍然是一种很好的做法,如果没有其他任何东西可以清楚地表明代码的意图。也有可能存在编译器无法优化的更复杂情况。

也是 llvm在线解析器演示 显示在那里也生成了相同的bitcode。如果关闭优化,则在没有const引用的情况下稍长一些。
* 1964字节 - 没有const引用(函数/参数没有其他的参数)
* 1960字节 - 只是没有const引用,但其他consts。
* 1856字节 - 带有consts和const引用。


4
2017-10-02 14:16



如果内联函数将a和b传递给另一个函数,则可能无法优化副本。例如,如果内联函数调用非内联函数 bar(a) 编译器必须复制,因为bar可能会这样做 if (&a == &special) ... 原来的来电者可能已经过去了 special。 - Raymond Chen
请尝试使用非POD类型。 - Ben Voigt
如果声明了成员函数,则优化器无关紧要 const 或不。对于优化器而言,const-correctness是不可见的,并且只是为了帮助程序员而设计的(如果违反const声明则通过给出编译时错误),而不是优化器。 - 6502
@ 6502:const-correctness在某些情况下会影响优化,虽然我同意,但成员函数的constness不是其中之一。 - Ben Voigt
@Ben Voigt:影响优化的是const 值。参考的常数(如 const X &)或指针(如。) const X *)对于优化器来说永远不是一个帮助,因为它是一个声明,它没有说明被引用或指向的对象的常量(这些声明只确定哪些操作对指针/引用有效)。 - 6502


根据数据类型,按引用传递的速度快于值。
但是对于内联函数,函数体(以及因此所有引用/传入的值)被添加到它们被使用的代码行中,因此从技术上讲,没有传递变量,在同一区域中只有更多行代码。

参考 http://www.cprogramming.com/tutorial/lesson13.html

在这个问题上也有一个非常有用的答案 应-I-取参数到内联函数按引用或 - 值

  • 示例可能具有误导性,删除 -

1
2017-10-02 13:33



这完全是猜测。 - pmr
通过引用传递比按值传递更快 取决于类型。此外,使用引用的代码还有其他要求(用于正确处理别名),并且可能需要对值传递的本机类型不需要额外的间接。 - 6502
道歉,由于一些奇怪的原因,我通过指针与值混合传递,你是对的,它只对某些数据类型更快。我也指出你 stackoverflow.com/questions/722257/... 这支持了我的观点 - Serdalis