为什么sv后缀引入的字符串不过期?

L. *_* F. 1 c++ language-lawyer string-view c++17

std::string_view使用临时初始化a是一个常见的错误std::string

using namespace std::literals;

std::string_view sv1 = "foo" ; // good
std::string_view sv2 = "bar"s; // bad: "foo"s will expire

std::cout << sv1 << "\n"       // outputs foo
          << sv2 << "\n";      // undefined behavior
Run Code Online (Sandbox Code Playgroud)

这是因为"bar"s,临时表达式std::string完整表达式的末尾被销毁了。

但是"foo"sv呢?

std::string_view sv3 = "baz"sv;
Run Code Online (Sandbox Code Playgroud)

当然这应该起作用,因为后缀sv否则是没有用的。但是,这与之"baz"s有何根本区别?换句话说,为什么引入的字符串"baz"sv不过期?

L. *_* F. 6

为什么声明sv2不好

[basic.string.literals] / 1

string operator""s(const char* str, size_t len);
Run Code Online (Sandbox Code Playgroud)

返回: string{str, len}

在中"foo"s,字符串文字"foo"用于初始化临时文件std::string。字符被复制到临时的基础数组std::stringstd::string_view是一个非所有者视图,sv2指向临时的基础数组std::string。临时文件std::string销毁后,sv2继续指向(现已过期)基础数组,并尝试输出sv2结果导致未定义的行为。

为什么声明sv3

[string.view.literals] / 1

constexpr string_view operator""sv(const char* str, size_t len) noexcept;
Run Code Online (Sandbox Code Playgroud)

返回: string_­view{str, len}

因此,的声明sv3等于:1

std::string_view sv3{"baz", 3};
Run Code Online (Sandbox Code Playgroud)

sv3直接指向字符串文字"baz"。字符串文字具有静态存储期限,并且不会过期。

1这里有些微妙之处。复制省略可能会可能不会适用于此。由于string_views是非所有者,因此复制string_views不会引入新的临时字符串。因此,无论是否要进行复制,其状态sv3都相同。

  • 即使没有复制,`sv3`也是安全的,因为看不到堆或栈。无需费吹灰之力,就会使用可执行文件本身的数据创建一个非所有者临时文件,我们称其为“全局数据”。当它的指针/大小被复制到函数边界上的`sv3`时,临时文件将被销毁,但是由于它不是所有者,因此不会释放任何内存,因为它始终是二进制文件中段的一部分。因此,现在“ sv3”是进入该内存的安全视图。 (3认同)
  • @LF我同意复制省略是不错的选择,但是您对它的强调如此之大,以至于听起来要使“`sv3`直接指向字符串文字””“ baz”`”为真,复制省略是必要的。当前,您读到:“为什么sv3的声明很好-&gt;因此,通过保证复制省略(...)”。因此,后续问题将是“ string_view`副本如何?” 我们俩都知道它们也直接指向静态的“ baz”。我会指出“字符串文字具有静态存储期限,并且不会过期。” 首先提出标题问题,然后留下有关复制省略的说明。 (3认同)