当传递临时的std::string时,string_view的行为是什么?

16

我刚遇到了一些误解:至少在libc++实现中,std::experimental::string_view有以下简洁的实现:

template <class _CharT, class _Traits....>
class basic_string_view {
public:
   typedef _CharT value_type;
   ...
   template <class _Allocator>
   basic_string_view(const basic_string<_CharT, _Traits, _Allocator>& str):
       __data(str.data()), __size(str.size())
   {
   }

private:
   const value_type* __data;
   size_type __size;
};

这个实现是否意味着,如果我们将rvalue表达式传递给此构造函数,在构造完成后使用__data会得到未定义的行为?


1
是的。string_view只是一个被美化了的引用。 - Rapptz
1
参见:[https://dev59.com/nWIi5IYBdhLWcg3w8AFy]。 - Kerrek SB
1个回答

24

没错,一个 string_view 是一个非拥有的包装器,具有引用语义,只有在所引用的字符串的生命周期超出视图使用期间时才能使用。

典型用例是函数参数,在函数调用期间实际字符串存在,函数体从不存储视图,而仅 读取 它:

void foo(std::experimental::string_view message)  // pass by value
{
    std::cout << "You said, '" << message << "'.\n";
}

用法:

foo("Hello");       // OK, string literal has static storage
foo(s);             // OK, s is alive
foo(s.substr(1));   // OK, temporary lives until end of full-expression

结论是:如果你只需要字符串在函数体内使用,给函数一个 string_view 参数,它可以统一绑定到任何类型的字符串参数上。你不需要一个函数模板,复制 string_view 很便宜,而且你会免费获得一些漂亮的子字符串操作。相比之下,永远不要存储一个 string_view,但总是存储一个 string

struct X
{
    X(std::experimental::string_view s) : s_(s) {}

    std::string s_;     // NEVER have a string_view class member!
};

3
“Never”有些过于绝对了,但如果您确实要存储它,那么您需要像存储“char *”一样小心。 - plugwash
1
@plugwash:也许吧。但如果你存储视图,我会说你肯定偏离了信息传递的主旨。是的,在一个只用作 prvalue 的瞬态类中,你可能能够利用这一点,但这样的代码可能最好使用 lambda 表达式编写,以表明被查看的字符串长于可调用对象的声明周期。 - Kerrek SB

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