【问题标题】:Are templated arguments passed by const ref optimized to be passed by value when small enough?const ref 传递的模板化参数是否优化为在足够小的时候按值传递?
【发布时间】:2019-11-18 10:15:47
【问题描述】:

当标准函数接受模板化参数而不修改它时,它似乎总是接受const ref(例如:std::vector::insert)。

这是否意味着类似 bool 参数的函数将变为 std::vector<bool>::insert(const bool& value)

或者是否有一些优化使其变为std::vector<bool>::insert(bool value)?如果是,我自己的模板函数也会从中受益吗?

【问题讨论】:

  • 为什么要优化?
  • 通过值而不是引用传递布尔值不是更好吗? (据我了解,通过引用传递意味着传递变量的地址,例如大小为 8 位,而不是大小为 1 bool)
  • bool 是 1 个字节。顺便说一句,std::vector<bool> 是尝试将bool 优化到一位可能出错的最佳示例
  • 当调用被内联(向量模板就是这种情况)时,这无关紧要 - 编译器使用 const refs 对原始类型执行相同的优化。
  • 这样的函数很可能是内联的,所以没有任何物理传递。当它没有内联时,通常不可能进行这样的优化。

标签: c++ templates parameter-passing


【解决方案1】:

std::vector 是一个模板,因此std::vector<bool>::insert() 的定义是inline

现代编译器很容易“看穿”inline 调用中的引用并对其进行全面优化。

对于像int 这样的小对象,按引用传递和按值传递没有区别。

例子:

struct A {
    int func1(const int& x) { return x + 1; }
    int func2(int y) { return y + 1; }
};

int func1(int x) {
    A a;
    return a.func1(x);
}

int func2(int y) {
    A a;
    return a.func2(y);
}

生成的代码(godbolt link):

func1(int):                              # @func1(int)
        lea     eax, [rdi + 1]
        ret
func2(int):                              # @func2(int)
        lea     eax, [rdi + 1]
        ret

如果您通过共享库公开 API,那么通过引用传递可能会导致额外的取消引用。这是因为在 C++ ABI 中,按引用传递实际上是通过指针发生的。但是对于inline 调用,这通常不是问题。

另一方面,如果复制或使用它涉及副作用,则按值传递 large 对象可能不容易优化。因此,对于通用模板,通过引用传递是一种明智的设计选择。

【讨论】:

    猜你喜欢
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 2011-04-15
    • 2017-11-11
    相关资源
    最近更新 更多