поведение string_view при передаче временного std::string

Я просто столкнулся с некоторым недоразумением: по крайней мере, в реализации 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 после построения?


person Bikineev    schedule 17.11.2014    source источник
comment
Да. string_view — это просто прославленная ссылка.   -  person Rapptz    schedule 17.11.2014
comment
см. также.   -  person Kerrek SB    schedule 17.11.2014


Ответы (1)


Вот так. 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_views дешево, и вы получаете несколько аккуратных операций с подстроками бесплатно. Напротив, никогда не сохраняйте string_view, а всегда сохраняйте astring:

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

    std::string s_;     // NEVER have a string_view class member!
};
person Kerrek SB    schedule 17.11.2014
comment
Never немного суров, но если вы храните его, вам нужно проявлять такую ​​же осторожность, как и при хранении char * - person plugwash; 20.10.2016
comment
@plugwash: Может быть. Но я бы сказал, что вы определенно уйдете от сообщения, если сохраните представление. Да, в переходном классе, который используется только как значение prvalue, вы можете использовать это, но такой код, вероятно, лучше писать с лямбда-выражениями, которые дают понять, что просматриваемая строка переживет вызываемую. - person Kerrek SB; 20.10.2016