是否使用对象的指针和引用作为函数参数更轻

Is using pointers and references of an object as function arguments lighter?

本文关键字:函数 参数 引用 对象 指针 是否      更新时间:2023-10-16

我想知道是否:

//Let's say T is a big class with + operand implemented.
T add(T* one, T* two)
{
     return *one + *two;
}

和:

T add(T& one, T& two)
{
    return one + two;
}

比这轻:

T add (T one, T two)
{
     return one +two;
}

如果不是,那么如果没有任何东西会改变对象的数据,为什么有人会使用指针或对对象的引用而不是对象本身作为函数的参数?

对于光类型,即适合寄存器的光源类型,例如 int ,这没有区别,因为它们就像指向它们的指针一样容易复制。实际上,额外的间接寻址可能会损害性能,这就是为什么在不需要时应避免引入它的原因。
但是,所使用的类型复制成本可能很高。每天的例子是std::string。引用避免复制,并且在函数需要"重"对象的地方受到青睐。

在函数模板中,在采用各种对象类型时通常应使用引用,除非您确定唯一涉及的类型是"轻量级",例如迭代器或标量。
不过,这条规则也有不太明显的例外。考虑std::accumulate

template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );

在这里,init是按价值获取的。原因很简单:在通常的实现中,init修改,因为它直接在计算中使用 - 没有引入中间对象。

template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init)
{
    for (; first != last; ++first) {
        init = init + *first; // Here
    }
    return init;
}

指针本身不应用于间接函数参数。它们在 C 中使用,其中不存在引用。

使用基元类型时,按指针或引用传递它并不比按值传递轻。但如果它是一个大对象,则按指针或引用传递将比按值传递轻,因为复制大对象的开销。

如果"更轻"的意思是"更有效率",答案(对于整数)是否定的——唯一一次通过指针或引用传递参数可能比按值传递更有效,如果你传递的对象非常大(例如 sizeof(theObjectType) 明显大于指针的典型大小的 4 或 8 个字节), 或者,如果对象的类具有复制构造函数,其实现在计算上是昂贵的。 请注意,当通过指针或引用传递时,CPU 在访问数据时必须取消引用指针/引用,这并非完全免费。

如果不是,那么为什么有人会使用指针或对对象的引用 而不是对象本身作为函数的参数,如果没有的话 会改变对象的数据吗?

可能是他们想要向函数传达对象的特定实例,而不是(仅)对象的内容。 例如,可以(尽管做法不好)编写一个函数,如果您传入指向特定全局对象的指针,该函数的行为与在任何其他指针中传递时的行为不同。

通过指针传递还为调用方提供了将 NULL 作为参数传入的选项,如果您希望调用方能够指定"未为此参数提供任何值",这将非常有用。

答案一如既往

视情况而定。

如果您想知道复制或通过引用传递是否更便宜,或者正确的事情,请考虑以下事项:

  1. 与指向对象的指针相比,复制对象的成本有多高。
    无论如何,根据参数的传递方式,有时可以省略副本。

    对于int,指针/引用充其量不会更昂贵。

  2. 请记住,减少混叠有好处。
  3. 请记住,你总是可以无情地掠夺按值传递的参数,就像通过右值引用传递的参数一样。
    对其他人来说并非如此。

    并不是说这些考虑对int或其他类型不管理更昂贵的资源有影响。

  4. 完全省略论点有意义吗?
    在这种情况下,您必须通过指针传递,或使用类似 未来std::optional .
    如果不是,指针在语义上是错误的选择。

无论如何,永远不要传递非const指针或引用,除非它应该由函数修改。

此外,如果您认真对待性能,请始终进行衡量
请记住,大部分时间只花在代码的一小部分上。

不,您的最后一个版本是"更轻"。

但这是因为int参数可以很容易地在堆栈上传递。对于较大的数据类型、类等,传递指针更有效。

此外,如果您需要更改函数中某个参数的值,则需要一个指向它的指针(其中的引用是一种类型)才能修改它。