返回 const std::string& 的方法应该返回 const std::string_view 吗?

Posted

技术标签:

【中文标题】返回 const std::string& 的方法应该返回 const std::string_view 吗?【英文标题】:Should methods returning const std::string& return const std::string_view instead? 【发布时间】:2019-06-14 15:30:46 【问题描述】:

假设我们在一个类中有一个简单的 getter 方法,它返回一个 conststd::string 成员的引用:

const std::string& getString() const noexcept  return someString; 

随着 C++17 中 std::string_view 的出现,我想知道它是否有任何优势:

const std::string_view getString() const noexcept  return someString; 

一种方法比另一种方法有优势/劣势吗?显然(如果我错了,请纠正我)两种解决方案肯定会比这更好:

const char* getString() const noexcept  return someString.c_str(); 

我已经看到this 相关问题,但我要求的内容略有不同。

【问题讨论】:

【参考方案1】:

是的,你应该写:

const std::string& getString() const noexcept  return someString; 

而不是(注意:不是const,因为永远不会返回const 值):

std::string_view getString() const noexcept  return someString; 

原因是 - 你已经有一个string。因此,您无需支付任何额外费用即可从中获得string。并且string 与任意string_view 有一个显着的语义差异:保证它是null-terminated。我们知道这一点。也许一些下游用户需要依赖这些信息。如果他们需要空终止(例如,他们需要传递给一些需要它的 C API)并且您提供string_view,他们必须自己制作一个string。您什么都不保存,但可能会使下游用户做更多的工作。

但是,如果您有一个 vector<char> 代替......那么我建议返回一个 span<char const> 或等效的。因为没有语义差异,您只是提供一个视图。


还有what的单独参数:

auto x = obj.getString();

应该这样做。这要么获取string 的副本(昂贵,但安全),要么有效地引用它(便宜,但可能悬空)。但它看起来并不完全像一个参考,它看起来像一个值。这对于一般的引用语义类型来说是一个广泛的问题(例如reference_wrapperstring_viewspantuple<T&...>optional<T&>,如果存在的话等)。

我没有这个案子的答案,但有一点需要注意。

【讨论】:

关于第二部分:我认为在const std::string& 的情况下,生命周期延长会起作用,这可能是你在使用string_views 时松动的东西......这可能是另一个更喜欢的论点const 引用而不是字符串视图? 我已经看到了太多由于假设 std::string 为空终止而导致的错误。除非使用 c_str(),否则我建议永远不要假设。当然,它碰巧是有保证的,但是当您希望编译器捕获错误的代码进行更改时,不要高兴地给出指向 std::vector 的指针,其中有人假设 *v.end() 是指向的合法指针一个空终止符。 @andreee 生命周期延长只有在你的 getter 返回一个prvalue std::string getString() 时才会生效。你会有一个悬空的参考做auto& str = make_obj().getString() @ZanLynx 你是什么意思? std::string guarantees null-termination on 基本上 every kind 自 C++11 以来的访问... @FabioFracassi 所以右值重载返回string,左值返回string_view?不知道我对此有何感想。 (另外,嗨法比奥!)

以上是关于返回 const std::string& 的方法应该返回 const std::string_view 吗?的主要内容,如果未能解决你的问题,请参考以下文章

const char*、const char(&)[N] 和 std::string 的函数重载

将 std::string_view 传递给执行 const std::string& 的 API

为啥 g++ 不关心初始化列表分配给 (const std::string&) a (std::string)?和其他怪异[关闭]

为啥编译器更喜欢 f(const void*) 而不是 f(const std::string &)?

c++,为啥要使用 const std::string & parameterName? [复制]

传递给第三方 API 时的 C++ const std:string& 安全性