【发布时间】:2019-01-20 19:41:50
【问题描述】:
考虑这个例子:
#include <utility>
// runtime dominated by argument passing
template <class T>
void foo(T t) {}
int main() {
int i(0);
foo<int>(i); // fast -- int is scalar type
foo<int&>(i); // slow -- lvalue reference overhead
foo<int&&>(std::move(i)); // ???
}
foo<int&&>(i) 是否与foo<int>(i) 一样快,还是像foo<int&>(i) 那样涉及指针开销?
编辑:按照建议,运行 g++ -S 给了我相同的 51 行汇编文件 foo<int>(i) 和 foo<int&>(i),但 foo<int&&>(std::move(i)) 产生了 71 行汇编代码(看起来差异来自 @ 987654330@)。
编辑:感谢那些推荐具有不同优化级别的 g++ -S 的人——使用 -O3(并制作 foo noinline)我能够获得类似于 xaxxon's solution 的输出。
【问题讨论】:
-
过早优化?
-
好吧,从语义上讲,在右值引用的情况下可以进行双重复制,但对于实际情况,我希望编译器使用指针 - 毕竟,带有真实的代码(不是由 std::move 制作的) 右值(和大的右值 - 比如说,即时构造的 std::vector )会更好地使用 pass-by-non-const-pointer
-
“运行 g++ -S 给了我相同的 51 行汇编” - 尝试使用不同的优化级别(
-O1vs--O2vs-O3vs-Os)。 -
我第二个@JesperJuhl:没有
-Os,-S几乎没有意义,尤其是没有-O0或-O3。只有-S -Os产生近乎可读的汇编代码,显示实际发生的情况。也就是说,您的模板foo<>甚至没有尝试 来实际使用它的参数。优化器将丢弃您尝试查看的内容。为了正确分析,定义三个非模板函数,如int foo_noref(int arg) { return arg; }在单独的文件中,并使用-S -Os编译。然后对调用void bar_noref() { int i = 0; foo_noref(i); }执行相同操作。 -
是的,它添加了指针,因此引用对象的所有使用都将涉及指针间接。另一方面,如果您引用的对象更大,那么按值传递可能会调用制作副本的所有成本,即使您当时只访问了函数中的一个成员。按值将对象传递给另一个方法,然后制作另一个副本。有时这是您想要做的,但通常按值传递简单值并通过 const ref 传递较大对象是一个好策略。
标签: c++ c++11 overhead pass-by-rvalue-reference