返回const std::string&的方法是否应该改为返回const std::string_view?

19

假设我们在一个类中有一个简单的getter方法,该方法返回一个指向std::string成员的const引用:

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(); }

我看到了这个相关的问题,但是我要求的略微不同。

1个回答

24

是的,你应该写:

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

不要返回const值,而是:

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

- 您已经有一个字符串,因此不必额外花费任何费用来获取字符串。而且字符串与任意字符串视图的一个显着语义差异在于:它是保证以空字符结尾的。我们知道这个。也许某些下游用户需要依赖该信息。如果它们需要空终止(例如,它们需要传递给某些需要它的C API),并且您提供了一个字符串视图,则它们必须自己制作一个字符串。你什么都没省,但可能会让下游用户做更多的工作。

但是,如果您有一个vector<char>,那么我建议返回span<char const>或等效物。由于没有语义差异,并且您只提供一个视图。


还有一个单独的参数的论点:

auto x = obj.getString();

这可能需要对 string 进行复制(代价高但安全)或者传递一个指向它的引用(代价低但有悬空风险)。但是这看起来不完全像引用,而更像一个值。这是参考语义类型普遍存在的问题(例如像 reference_wrapperstring_viewspantuple<T&...>optional<T&> (如果有的话)等等)。

我没有针对这种情况的答案,但这是需要注意的问题。


1
关于第二部分:我认为在 const std::string& 的情况下,寿命延长会发挥作用,而在使用 string_view 时可能会失去这个功能... 这可能是支持使用 const 引用而不是 string view 的另一个论点吗? - andreee
我见过太多由于假定std::string为null终止而导致的错误。除非使用c_str(),否则我建议永远不要假定。当然,它被保证是这样的,但是当代码发生更改时,您希望编译器捕获错误,而不是愉快地提供指向std::vector<char>的指针,其中某人假定*v.end()是空终止符的合法指针。 - Zan Lynx
1
@andreee 只有当你的getter返回一个prvalue std::string getString()时,lifetime extension才会生效。如果你执行auto& str = make_obj().getString(),你将会得到一个悬空引用。 - Guillaume Racicot
2
@ZanLynx 你是什么意思?自C++11以来,std::string在基本上每种访问方式上都保证空终止。这包括每种类型的访问。 - Max Langhof
1
@FabioFracassi 那么右值重载返回一个string,左值重载返回一个string_view?不知道我对此有什么感觉。(另外,嗨Fabio!) - Barry
显示剩余4条评论

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