【问题标题】:std::tie vs std::make_tuplestd::tie 与 std::make_tuple
【发布时间】:2017-04-16 07:10:49
【问题描述】:

This code compiles 但我想知道应该首选哪个版本:

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

由于该函数按值返回一个元组,因此使用std::tie 应该没有任何问题,对吧? (即没有悬空引用)

【问题讨论】:

    标签: c++ tuples


    【解决方案1】:

    小心std::tie。返回 tie 在逻辑上等同于返回引用,并附带所有注意事项。

    从逻辑上讲,这三个是等价的:

    int& foo();
    std::reference_wrapper<int> foo();
    std::tuple<int&> foo();
    

    还有这个:

    int a = 10;
    return std::tie(a);
    

    等价于:

    int a = 10;
    return std::ref(a);
    

    因为它产生以下之一:

    std::tuple<int&>
    

    在您的示例中,您可以通过返回值的隐式转换来保存。但是,将返回类型替换为auto 会发现逻辑错误:

    #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】:

      tuple2 应该更高效。 tie 确实创建了一个tuple,但是关于tie,您必须记住的是它不会创建Args... 类型的元组,而是创建Args&amp;... 类型的元组,这意味着您的返回类型和您的元组不符合。这意味着您需要从绑定元组复制到返回元组。

      在第二个示例中,您将返回一个与返回类型具有相同类型的元组,因此您可以直接返回它。您不必在那里复制。

      【讨论】:

      • 返回对局部变量的引用总是一个错误。这里的保存是由于隐式转换为返回类型,仍然会创建一个值的元组。
      【解决方案3】:

      std::tie 不会做你认为的那样。
      std::tie 返回一个tuple of references 到传递的元素,所以在return_tuple1() 中,实际发生了什么是:

      tuple<int, int, int> return_tuple1() {
          int a = 33;
          int b = 22;
          int c = 31;
          return std::tuple<int&,int&,int&>(a,b,c);
      }
      

      然后,返回类型tuple&lt;int, int, int&gt; 自建来自std::tuple&lt;int&amp;,int&amp;,int&amp;&gt;

      现在,编译器可能优化这个结构,但我不会打赌。使用std::make_tuple,因为它是完成该任务的正确工具。

      【讨论】:

      • 另外std::make_tuple 更好地表达了代码的意图。如果我看到调用std::tie 的代码然后将其存储在tuple 中,我可能会认为这是一个错误。
      猜你喜欢
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 2016-03-14
      • 2017-04-04
      • 2015-09-25
      相关资源
      最近更新 更多