std::tie vs std::make_tuple

为君一笑 提交于 2019-12-23 07:01:24

问题


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)


回答1:


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;
}



回答2:


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.




回答3:


tuple2 should be more efficient. tie does create a tuple but the thing you have to remember about tie is that it does not make a tuple of type Args... but instead makes a tuple of type Args&... meaning your return type and your tuple do not match. That means you need to copy from the tied tuple to the return tuple.

In the second example you are returning a tuple with the same type as the return type so you can return that directly. You do not have to copy there.



来源:https://stackoverflow.com/questions/40914165/stdtie-vs-stdmake-tuple

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!