通过引用传递 std::string_view

6

最近,在代码审查中,我遇到了传递引用的std::string_view参数。例如以下代码:

void fun(std::string_view a);

变成

void fun(std::string_view& a);

我认为以下几点令人困扰:
  • 现在只能使用l-value std::string_view来调用。
  • 使用std::string_view的核心目的是避免复制底层字符串,因此我认为使用&没有意义。
问题在于,将std::string_view参数声明为按引用传递是否有任何优势?

4
您可能是指除了左值 lvalue string_view 之外的其他内容? - StoryTeller - Unslander Monica
1
也:相关,可能是重复问题 https://dev59.com/6V4d5IYBdhLWcg3wCOyD - StoryTeller - Unslander Monica
你当前所写的是指传递可变引用,还是 const&?如果没有 const,那么语义上会有很大的不同,原始对象在被调用方内是可变的,因此我期望 fun 会改变操作数的状态。const& 类型在不变性方面更接近于按值传递,但仍然不完全相同。如果你对状态的承诺与按值传递相同,即根本不可能发生任何变化,并且你考虑使用引用只是为了提高性能,那么我同意 @StoryTeller 在另一个问题中的答案涵盖了你的主题。 - luk32
1个回答

7
这个问题有点不清楚,因为它们的语义非常不同。
传递非const引用意味着通过参数返回 - 也就是说,您在某个时刻修改函数内部的值,并且可能使用或不使用原始输入值。由于您只能将string_view指向其他内容,而不允许修改其内容。因此,我应该期望以下结果-函数使用输入的string_view做一些事情,然后稍后将这个输入string_view指向其他内容。一个语义上的改进是:
  void fun(std::string_view& a);

改进版:

 std::string_view fun(const std::string_view& a);

更好的解决方案(从语义上来说):
 std::string_view fun(std::string_view a);

现在提供输入更容易,并且我可以自己选择是否要将我的输入string_view重新指向。


除此之外,由于以下原因,引用存在劣势:

  • 从语义上讲,拷贝更好:比起引用(即使是const类型的引用),拷贝更容易理解。
  • 如果也考虑性能,引用在大多数情况下都处于劣势,并且充其量只能大致与拷贝相媲美。使用clang进行演示:https://godbolt.org/z/UR68km(结果可能因编译器而异)。

请注意,即使复制结果稍微慢一点,仍应将其视为首选的传递方法。


我通常在编写函数时使用以下助记符:

通过const引用传递,通过值返回。除非可以,否则优先传递值。

这在这里非常合适。当您不需要担心可能存在较大数据复制的情况时,可以使用值传递(有时引用是唯一的选择)。使用这个经验法则可以确保您不会因意外而进行额外的大量数据复制。除了标量之外,应该通过值传递最显著的类类型是那些属于代理类别的类型(例如智能指针和视图)。

只有在修改缓冲区时才很少通过非const引用传递 - 指针的情况也是如此。


1
我发现使用引用传递的一个场景是在提取“标记”时。例如,std::string_view ExtractNextToken(std::string_view& buffer) 的声明。这种方式下,参数本质上像队列一样处理,从缓冲区中弹出标记。空字符串视图表示没有更多标记可提取(也可以检查buffer.size() == 0)。所有其他情况,传值/复制似乎是正确的方法。 - bgura

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接