【问题标题】:Const function's parameters: should it be passed by reference or not?const 函数的参数:是否应该通过引用传递?
【发布时间】:2013-11-08 15:38:39
【问题描述】:

我最近去面试一个程序工作,他们要求我编写一些函数,该函数将向量和整数作为参数。任务是计算向量中大于、小于或等于整数的元素数量。我按照这些思路写了一些东西:

void printStat(const std::vector<int> &vec, const int &val)
{
    int results[3] = {0,0,0};
    for (int i = 0; i < vec.size(); ++i) {
        int option = (vec[i] == val) ? 0 : ((vec[i] > val) ? 1 : 2);
        results[option]++;
    }
    ...
}

他们对我认为可疑的代码发表了一些评论,我想知道 C++ 专家的意见。他们说通过引用传递vecval 的效率低于通过值传递。写起来会更好:

void printStat(const std::vector<int> vec, const int val) {}

说实话,我一直使用第一个版本(在顶部)编写我的代码,并没有真正的论据来解释为什么我的方法会比他们的更好或没有什么不同。他们的论点是,通过引用传递参数会迫使稍后在您想要其内容时取消对变量的引用,这比我通过值传递变量时要慢。

所以我的问题是:最好的方法是什么,原因是什么?

奖励问题:他们还认为,在循环中使用迭代器会比使用 [] 运算符访问向量的元素更有效。我看不出有什么原因,尤其是我怀疑vec[i] 在第 5 行被访问两次时会在 L1 缓存中。

谢谢。

【问题讨论】:

  • 哦,哇,一堆废话。显然,他们过于关心“效率”(而且他们似乎对它有一些模糊的定义)并且完全无视语义。我不会接受这份工作。
  • 传递const int&amp; 没有任何好处,但传递对std::vector 的引用却有很多好处。
  • 是的,我同意int&amp;,但与写const int val相比,这样做会受到惩罚吗?
  • @user18490 是的,可能会受到惩罚 - 根据 Joachim 的回答,您最终可能会(有效地)传递一个 64 位指针而不是单个 32 位值。不过,这不会是一个重大的处罚。
  • @user18490:是的,通过引用传递(几乎可以肯定)需要额外的间接级别来访问对象。编译器可能会也可能不会优化它;如果您按值传递,则不必。对于像vector 这样的大型或复杂对象,复制的成本可能高于间接成本,因此您应该通过引用传递它。

标签: c++ performance pass-by-reference


【解决方案1】:

这取决于您将如何使用vec。如果向量中没有很多条目,可以按值传递它,因为复制会很快。但一般来说,通过引用传递它更“有效”。

另一方面,val 参数对于本机类型通常不需要将它们作为常量引用传递。实际上,由于引用通常(如果不总是?)实现为引擎盖下的指针,因此将此参数作为引用传递将在 64 位机器上传递 64 位值,而普通 int 则传递 32 位值.由于这是一个指针,它也将使用额外的间接性。

【讨论】:

  • 感谢您的所有回答。他们很好,很清楚。关于 64 位机器上的指针占用比值本身更多的点。
  • @user18490 关于int 与指针(参考)的大小,这不是其他人指出的大问题,而是额外的间接性。
  • 很好,谢谢。一般来说,这是正确的,但在这种特殊情况下,一旦间接访问 val 的内容,我会假设 val 将存在于 L1 缓存中。第二次访问它是否需要另一个间接。按值传递变量会导致复制操作本身有成本?
【解决方案2】:

通过 ref 传递内置类型的对象会导致额外的负载。如果你想防止它被修改,只需使用 const int val。通过 ref 使用 std::vector 似乎绝对高效。

【讨论】:

    【解决方案3】:

    我会坚持通过 const 引用传递对象。一个例外是,如果无论如何都进行了复制(const T 没有任何意义,除了防止函数实现中的意外更改)。

    但是:我改变了实现operator =的方式。

    T& operator=(const T& other) {
       T(other).swap(*this);
       return *this;
    }
    

    T& operator=(T other) {
       other.swap(*this);
       return *this;
    }
    

    允许复制省略和移动语义。

    【讨论】:

    • 你忘记operator关键字后面的=了吗?
    • (虽然这是固定的)
    猜你喜欢
    • 2014-05-29
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    • 1970-01-01
    相关资源
    最近更新 更多