这在最近的代码审查讨论中提出,但没有令人满意的结论。有问题的类型类似于 C++ string_view TS。它们是围绕指针和长度的简单非拥有包装器,装饰有一些自定义函数:
#include <cstddef>
class foo_view {
public:
foo_view(const char* data, std::size_t len)
: _data(data)
, _len(len) {
}
// member functions related to viewing the 'foo' pointed to by '_data'.
private:
const char* _data;
std::size_t _len;
};
问题出现了,是否有一个论点是更喜欢通过值或 const 引用传递此类视图类型(包括即将到来的 string_view 和 array_view 类型)。
支持按值传递的论点相当于“减少输入”,“如果视图具有有意义的突变,则可以改变本地副本”,以及“可能不会降低效率”。
支持按常量引用传递的论点相当于“通过 const& 传递对象更惯用”,并且“可能效率不低”。
是否有任何其他考虑因素可能最终以一种或另一种方式摇摆论点,即通过值还是通过 const 引用传递惯用的视图类型是否更好。
对于这个问题,可以安全地假设 C++11 或 C++14 语义,以及足够现代的工具链和目标架构等。
原文由 acm 发布,翻译遵循 CC BY-SA 4.0 许可协议
如有疑问,请按值传递。
现在,您应该很少有疑问。
通常,通过价值的代价很高,而且几乎没有什么好处。有时,您实际上想要对存储在其他地方的可能变异值的引用。通常,在通用代码中,您不知道复制是否是一项昂贵的操作,因此您宁可不这样做。
有疑问时应该按值传递的原因是因为值更容易推理。当您调用函数回调或您拥有的东西时,对外部数据的引用(甚至是
const
一个)可能会在算法中间发生变异,从而将看似简单的函数渲染成复杂的混乱。在这种情况下,您已经有一个隐式引用绑定(到您正在查看的容器的内容)。添加另一个隐式引用绑定(到查看容器的视图对象)同样糟糕,因为已经存在复杂性。
最后,编译器对值的推理比对值的引用更好。如果您离开本地分析的范围(通过函数指针回调),编译器必须假定存储在 const 引用中的值可能已经完全改变(如果不能证明相反的话)。可以假定自动存储中的值没有人指向它的指针不会以类似的方式进行修改——没有定义的方式来访问它并从外部范围更改它,因此可以假定这种修改不会发生.
当您有机会将值作为值传递时,请拥抱简单性。它只是很少发生。