使用std::pair或std::tuple的移动语义

24

假设您想利用移动语义,但是您的一个可移动类需要成为std::pair的一部分。 目的是创建一个函数,返回可以被视为 rvalue 并转发的 std::pair

但我无法看出如何实现这一点,除非对std::pair本身进行内部更改,使其了解移动语义。

考虑以下代码:

struct Foo
{
 Foo() { }

 Foo(Foo&& f) { }

 private:

 Foo(const Foo& f) { } // do not allow copying
};

int main() 
{
 Foo f;
 std::pair<Foo, int> res = std::make_pair(f, 10); // fails due to private copy constructor
}
问题在于 std::make_pairstd::pair 构造函数本身都会接受两个对象并尝试制作它们的内部副本。这将导致尝试调用复制构造函数。但在我的示例中,我希望能够将新的 pair 对象移动res 中,并确保不进行任何拷贝操作。我认为除非std::pair 本身内部定义以下构造函数,否则不可能实现这一点:
pair(T1&& t1, T2&& t2) : first(std::move(t1)), second(std::move(t2))

但是在我使用的编译器(gcc 4.3.2)上似乎不行。可能是我的编译器版本太旧了,在更新版本中实际上会有这个支持移动语义的构造函数。但是我对移动语义的理解有些模糊,所以我不确定是否漏掉了什么。那么,我尝试做的事情是不是可能的,而不必重新实现 std::pair?还是说我的编译器过时了?

2个回答

20

然而,被调用的并不是std::pair的构造函数。实际上会调用std::pair的移动构造函数,而移动构造函数应该会按照您所期望的方式执行(参见N3126 20.3.5.2/6):

template<class U, class V> pair(pair<U, V>&& p);

效果:构造函数使用std::move(p.first) 初始化第一个值,使用std::move(p.second) 初始化第二个值。

然而,你的示例应该失败,因为在 std::make_pair(f, 10); 中,f 是左值,需要显式进行move,否则将会被拷贝。以下代码应该可以运行:

std::pair<Foo, int> res = std::make_pair(std::move(f), 10);

此外,请检查您的编译器是否具有适当的std::make_pair重载。您可能需要直接使用std::pair构造函数。 - user9876

2

GCC 4.3.2的实现不完整。pair(和tuple)应该有移动构造函数:

template<class U, class V> pair(U&& x, V&& y);

影响:构造函数使用std::forward(x)初始化第一个参数,使用std::forward(y)初始化第二个参数。
template<class U, class V> pair(pair<U, V>&& p);

效果:构造函数首先使用std::move(p.first)初始化第一个元素,然后使用std::move(p.second)初始化第二个元素。
(来自n3126中的[pairs.pair])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接