将 `std::string` 临时传递到 `std::string_view` 参数是否安全?

Is it safe to pass an `std::string` temporary into an `std::string_view` parameter?

假设我有以下代码:

void some_function(std::string_view view) {
    std::cout << view << '\n';
}

int main() {
    some_function(std::string{"hello, world"}); // ???
}

some_function 中的 view 会指代一个已经被摧毁的 string 吗?我很困惑,因为考虑到这段代码:

std::string_view view(std::string{"hello, world"});

产生警告(来自 clang++):

warning: object backing the pointer will be destroyed at the end of the full-expression [-Wdangling-gsl]

有什么区别?

(奇怪的是,使用大括号 {} 而不是方括号 () 来初始化上面的 string_view 消除了警告。我也不知道为什么会这样。)

明确地说,我理解上面的警告(string_viewstring 长,所以它持有一个悬空指针)。我要问的是为什么将 string 传递给 some_function 不会产生相同的警告。

std::string_view 就是 std::basic_string_view<char>,所以让我们看看它是 documentation on cppreference:

The class template basic_string_view describes an object that can refer to a constant contiguous sequence of char-like objects with the first element of the sequence at position zero.

A typical implementation holds only two members: a pointer to constant CharT and a size.

突出显示的部分 告诉我们为什么 clang 关于 std::string_view view(std::string{"hello, world"}); 是正确的:正如其他人评论的那样,这是因为在声明完成,std::string{"hello, world"} 被销毁,std::string_view 持有的底层指针悬垂。

显然这只是一个典型的实现,但既然我们知道它是正确的,它至少告诉我们标准不需要任何实现来做一些特殊的事情来保持活着的临时工。

Is it safe to pass an std::string temporary into an std::string_view parameter?

总的来说,它不一定安全。这取决于函数的作用。如果你不知道,那么你不应该认为它是安全的。

知道如图所示的函数定义,用临时字符串调用示例函数是安全的。

Will view inside some_function be referring to a string which has been destroyed?

在这种情况下不是,因为字符串视图引用的临时参数字符串尚未被销毁。


What's the difference?

函数参数的生命周期比作为参数传递的临时变量的生命周期短。字符串视图变量的生命周期比传递给构造函数的临时参数的生命周期长。

some_function(std::string{"hello, world"}); 是完全安全的,只要该函数不保留 string_view 供以后使用。

临时std::string在这个完整表达式的末尾被销毁(粗略地说,在;处),所以它在函数returns.[=18之后被销毁=]


std::string_view view(std::string{"hello, world"}); 总是会产生悬垂的 string_view,无论您使用 () 还是 {}。如果括号的选择影响编译器警告,则为编译器缺陷。

正如其他人所说,some_function(std::string{"hello, world"}); 是完全安全的,因为它按值传递它并保留在范围内直到函数结束。如果您只关心安全性,那就可以了,如果性能可能是个问题,我建议在这里使用右值引用,如下所示:

void some_function(std::string_view&& view)
{
    std::cout << "rval reference: " << view << '\n';
}

int main()
{
    some_function(std::string{"hello, world"});
}

R 值引用 如果您主要将 some_function() 用于临时值,则非常有用。