Reputation: 437
Suppose I have the following code:
void some_function(std::string_view view) {
std::cout << view << '\n';
}
int main() {
some_function(std::string{"hello, world"}); // ???
}
Will view
inside some_function
be referring to a string
which has been destroyed? I'm confused because, considering this code:
std::string_view view(std::string{"hello, world"});
Produces the warning (from clang++
):
warning: object backing the pointer will be destroyed at the end of the full-expression [-Wdangling-gsl]
What's the difference?
(Strangely enough, using braces {}
rather than brackets ()
to initialise the string_view
above eliminates the warning. I've no idea why that is either.)
To be clear, I understand the above warning (the string_view
outlives the string
, so it holds a dangling pointer). What I'm asking is why passing a string
into some_function
doesn't produce the same warning.
Upvotes: 6
Views: 3045
Reputation: 28520
std::string_view
is nothing other than std::basic_string_view<char>
, so let's see it's documentation on cppreference:
The class template
basic_string_view
describes an object that can refer to a constant contiguous sequence ofchar
-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.
The part I have highlighted tells us why clang is right about std::string_view view(std::string{"hello, world"});
: as others have commented it's because after the declaration is done, std::string{"hello, world"}
is destroyed and that underlying pointer that the std::string_view
holds dangles.
Clearly that's just a typical implementation, but since we know it is correct, it tells us at least that the standard doesn't require any implementation to do something special to keep temporaries alive.
Upvotes: 5
Reputation: 106
Just as others have said, some_function(std::string{"hello, world"});
is totally safe since it passes it by value and stays in scope until the function ends. If safety is all you are concerned with, that will do, if performance could be an issue, I'll recommend using an rvalue reference here like so:
void some_function(std::string_view&& view)
{
std::cout << "rval reference: " << view << '\n';
}
int main()
{
some_function(std::string{"hello, world"});
}
R-value references are great if you are going to use some_function()
mainly for temporary values.
Upvotes: 0
Reputation: 96934
some_function(std::string{"hello, world"});
is completely safe, as long as the function doesn't preserve the string_view
for later use.
The temporary std::string
is destroyed at the end of this full-expression (roughly speaking, at this ;
), so it's destroyed after the function returns.
std::string_view view(std::string{"hello, world"});
always produces a dangling string_view
, regardless of whether you use ()
or {}
. If the choice of brackets affects compiler warnings, it's a compiler defect.
Upvotes: 8
Reputation: 238491
Is it safe to pass an
std::string
temporary into anstd::string_view
parameter?
In general, it isn't necessarily safe. It depends on what the function does. If you don't know, then you shouldn't assume it to be safe.
Knowing the definition of the function as shown, it is safe to call the example function with a temporary string.
Will view inside some_function be referring to a string which has been destroyed?
Not in this case, because the temporary argument string - which the string view refers to - hasn't been destroyed.
What's the difference?
The parameter of the function has shorter lifetime than the lifetime of the temporary passed as the argument. The lifetime of the string view variable is longer than the lifetime of the temporary argument passed to the constructor.
Upvotes: 1