This code compiles but I'm wondering which version should be preferred:
#include <iostream>
#include <tuple>
using namespace std;
tuple<int, int, int> return_tuple1() {
int a = 33;
int b = 22;
int c = 31;
return tie(a, b, c);
}
tuple<int, int, int> return_tuple2() {
int a = 33;
int b = 22;
int c = 31;
return make_tuple(a, b, c);
}
int main() {
auto a = return_tuple1();
auto b = return_tuple2();
return 0;
}
since the function is returning a tuple by value there shouldn't be any problem in using std::tie
right? (i.e. no dangling references)
std::tie. Creates a tuple of lvalue references to its arguments or instances of std::ignore.
std::make_tupleCreates a tuple object, deducing the target type from the types of arguments.
Yes it does. A tuple holds variables by value, so it must copy the values into the tuple. If you want only their references copied, use pointers instead, i.e., boost::make_tuple(&objA,&objB) .
The new std::array and std::tuple containers provide developers with additional ways to manage structured data efficiently.
Be very careful with std::tie
. Returning a tie
is logically equivalent to returning a reference, with all of the caveats that come with it.
Logically, these three are equivalent:
int& foo();
std::reference_wrapper<int> foo();
std::tuple<int&> foo();
and this:
int a = 10;
return std::tie(a);
is equivalent to this:
int a = 10;
return std::ref(a);
because it produces one of these:
std::tuple<int&>
In your example you are saved by the return value's implicit conversion. However, replacing the return type with auto
reveals the logic error:
#include <iostream>
#include <tuple>
using namespace std;
auto return_tuple1() { // function name is now lying
int a = 33; // it should be return_chaos()
int b = 22;
int c = 31;
return tie(a, b, c);
}
auto return_tuple2() {
int a = 33;
int b = 22;
int c = 31;
return make_tuple(a, b, c);
}
int main() {
auto a = return_tuple1(); // uh-oh...
auto b = return_tuple2();
std::get<0>(a); // undefined behaviour - if you're lucky you'll get a segfault at some point.
std::get<0>(b); // perfectly ok
return 0;
}
std::tie
won't do what you think it does.std::tie
returns a tuple
of references to the elements passed, so in return_tuple1()
, what actually happens is :
tuple<int, int, int> return_tuple1() {
int a = 33;
int b = 22;
int c = 31;
return std::tuple<int&,int&,int&>(a,b,c);
}
then, the return type tuple<int, int, int>
builds itself from std::tuple<int&,int&,int&>
.
now, the compiler might optimize this construction away, but I wouldn't bet on that. use std::make_tuple
as it is the right tool for that task.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With