返回 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 方法,它返回一个 const
对 std::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_wrapper
、string_view
、span
、tuple<T&...>
、optional<T&>
,如果存在的话等)。
我没有这个案子的答案,但有一点需要注意。
【讨论】:
关于第二部分:我认为在const std::string&
的情况下,生命周期延长会起作用,这可能是你在使用string_view
s 时松动的东西......这可能是另一个更喜欢的论点const 引用而不是字符串视图?
我已经看到了太多由于假设 std::string 为空终止而导致的错误。除非使用 c_str(),否则我建议永远不要假设。当然,它碰巧是有保证的,但是当您希望编译器捕获错误的代码进行更改时,不要高兴地给出指向 std::vectorstd::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 &)?