我的问题在精神上类似于Avoid extra copywhen create a tuple from return value in C++,但因为我根本不理解答案,而且因为我正在谈论标准类型(即它们已经有移动构造函数)无论如何我都会问。
让我们假设 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
析构函数被调用两次,并且两次都释放了一些内存。 IE。所有情况都不是空字符串。
据我了解,随着移动构造函数的出现,应该可以避免临时的额外副本。
直接返回字符串时确实是这样:
#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
)。
我错过了什么?为什么它不能与
tuple
一起使用?有没有办法消除临时的额外副本,同时仍然返回 tuple
或类似的东西?
只需将
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) };
}
这是必要的,因为仅在返回的对象上执行到右值的自动转换。在这种情况下,
arg
不是要返回的对象;匿名std::tuple<std::string>
是。如果您希望移动 arg
,则必须使用 std::move
将其显式转换为右值。
请注意,这仍然需要移动构造元组中的对象,但这在大多数情况下通常没问题。您在问题中链接的答案显示了如何处理元组中的对象既不能复制也不能移动的情况,这种情况非常罕见。