I do not understand well enough why the second call of func
in the code below does not work:
#include <string>
#include <iostream>
#include <tuple>
using Tuple = std::tuple<const int&, const std::string&>;
void func(const Tuple& t)
{
std::cout << std::get<1u>(t) << std::endl;
}
int main()
{
const int n = 3;
const std::string text = "xyz";
func(Tuple(n, text));
//Does not work:
//func(Tuple(5, "abc"));
return 0;
}
When is the temporary string "abc"
destroyed?
EDIT1
So, finally, according to 康桓瑋 this works:
func(Tuple(5, std::string("abc")));
but this does not:
Tuple t(5, std::string("abc"));
func(t);
right? If yes what is the difference?
CodePudding user response:
Your second case is exactly what the standard wants to detect and forbid.
Since "abc"
is not a std::string
type, quote from P2255:
std::tuple<const std::string&> t("meow");
This construction always creates a dangling reference, because the
std::string
temporary is created inside the selected constructor oftuple
(template<class... UTypes> tuple(UTypes&&...)
), and not outside it. Thus, unlikestring_view
’s implicit conversion from rvaluestring
s, under no circumstances can this construction be correct.
And Tuple(5, "abc")
is no longer well-formed in C 23 thanks to P2255.
To prevent the destruction of temporary strings, you can explicitly specify the std::string
type such as func(Tuple(5, std::string("abc")))
.
CodePudding user response:
As hinted at in the comments, the problem is not with the parameter to the call to func
, per se, but with the second parameter to the Tuple
constructor.
You are attempting to assign a reference to a string constructed as a temporary object (from the given const char*
literal) to the second member of the tuple; when the constructor has completed/returned, that reference will invalid.
Some compilers may accept the code (MSVC does) and it may seem to work. However, clang-cl (in Visual Studio 2022) gives the following error when uncommenting the 'offending' line in your code:
error : reference member '_Val' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
However, note the the exact same error is shown if we replace your one-line call to func
with the following two lines:
Tuple tup = Tuple(5, "abc"); // Error on this line
func(tup);