代码之家  ›  专栏  ›  技术社区  ›  mark

在C++中,如何在没有临时额外副本的情况下返回字符串元组?

  •  1
  • mark  · 技术社区  · 1 年前

    我的问题在精神上与 Avoid extra copy when creating a tuple from return values in C++ ,但由于我根本不明白答案,而且我谈论的是标准类型(即它们已经有了move构造函数),所以我无论如何都会问它。

    让我们假设c++20。

    请考虑以下代码:

    #include <iostream>
    #include <tuple>
    using namespace std;
    
    static tuple<string> get_tuple()
    {
        string arg = "This is a long string allocated on the heap";
        return { arg };
    }
    
    void main()
    {
        auto [x] = get_tuple();
        cout << "x: " << x << endl;
    }
    

    在Visual Studio 2022调试器中运行此代码表明 string 析构函数被调用两次,两次都会释放一些内存。也就是说,没有一种情况是空字符串的情况。

    据我所知,随着move构造函数的出现,应该可以避免临时的额外副本。

    直接返回字符串时确实是这样:

    #include <iostream>
    using namespace std;
    
    static string get_tuple()
    {
        string arg = "This is a long string allocated on the heap";
        return arg;
    }
    
    void main()
    {
        auto x = get_tuple();
        cout << "x: " << x << endl;
    }
    

    但它不适用于 tuple (也不适用于 pair ).

    我错过了什么?为什么它不适用于 元组 ? 有没有办法在返回的同时取消临时额外副本的限制 元组 或者类似的东西?

    1 回复  |  直到 1 年前
        1
  •  2
  •   Miles Budnek    1 年前

    仅仅 std::move 将字符串插入 tuple :

    static std::tuple<std::string> get_tuple()
    {
        std::string arg = "This is a long string allocated on the heap";
        return { std::move(arg) };
    }
    

    Demo using a non-copyable type


    这是必要的,因为只对返回的对象执行到右值的自动转换。在这种情况下, arg 不是要返回的对象;一个匿名者 std::tuple<std::string> 是。如果你愿意 arg 若要移动,必须使用显式将其强制转换为右值 std::移动 .


    请注意,这仍然需要移动构造元组中的对象,但在大多数情况下这通常是可以的。您在问题中链接的答案显示了如何处理元组中的对象既不能复制也不能移动的情况,这是非常罕见的。