【问题标题】:C++ overloading operator, constant parameter or pass by value?C++ 重载运算符、常量参数还是按值传递?
【发布时间】:2020-12-30 13:47:13
【问题描述】:
template <typename T>
T operator+(T a, const T& b) {
    a += b;
    return a;
}

template <typename T>
T operator+(const T& a, const T& b) {
    T tmp {a};
    tmp += b;
    return tmp;
}

你有什么理由像第二个函数一样将参数作为常量引用传递,而不是像第一个函数那样直接按值传递,因为无论如何你都需要一个临时变量?


编辑 1:

我想我应该提一下,这 2 个替代函数仅用于处理带有左值参数的大小写,并且我将提供另外 2 个用于处理右值参数的函数,如下所示。

template <typename T>
T operator+(T&& a, const T& b) {
    a += b;
    return std::move(a);
}

template <typename T>
T operator+(const T& a, T&& b) {
    b += a;
    return std::move(b);
}

所以问题的重点是,为什么我需要显式创建一个临时变量(函数 2),而我可以让语言自动为我提供便利(函数 1)?

【问题讨论】:

  • 考虑a + b + c。当你通过值传递第一个参数时,你可以从a + b临时移动,当你通过const-ref传递时,你不能。
  • 我个人更喜欢第一种方法。也就是说,如果性能真的很关键,你应该对你的用例进行基准测试,看看哪个最适合你。

标签: c++ operator-overloading parameter-passing


【解决方案1】:
template <typename T>
T operator+(T a, const T& b) {
    a += b;
    return a;
}

在这里,您正在复制在此处传入的变量 a,然后您正在更新副本。这需要创建三个副本,并且您再次按值返回。

template <typename T>
T operator+(const T& a, const T& b) {
    T tmp {a};
    tmp += b;
    return tmp;
}

在这里,您的 tmp 变量具有局部范围,变量 a 是 const 引用,因此不允许修改 a 的值。 您正在返回一个 temp 的副本,它是一个局部变量。

两者都可以正常工作,但不同之处在于创建的副本数量。您在第一种情况下制作的副本比在第二种情况下要多。

虽然第二个将针对 tmp 变量进行优化以使用移动语义以减少副本。所以你在第二种情况下会有更快的性能

【讨论】:

  • 编译器将优化返回的副本以使用移动语义
  • 认为 @Mouse 暗示在第一个 sn-p 中不允许使用 NRVO,因为 a 也是一个函数参数。第二个 sn-p 避免了这一点。
  • godbolt.org/z/M8f8os dummy 示例,第二个只会复制,第一个复制并移动
  • @Bathsheba 好电话。我忘记了函数参数不符合 RVO 的条件。
  • 第一个允许将子表达式的临时结果移动到 lhs 参数中。第二个将始终复制在那里。与多余的举动相比,这可能是一种悲观。
猜你喜欢
  • 1970-01-01
  • 2018-09-25
  • 2021-02-02
  • 2019-08-17
  • 2016-03-10
  • 2014-04-08
  • 1970-01-01
  • 2014-07-24
  • 1970-01-01
相关资源
最近更新 更多