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

时间:2010-11-04 14:16:33

标签: c++ c++11 move-semantics std-pair move-constructor

假设您想要利用移动语义,但您的一个可移动类需要成为std::pair的一部分。目的是创建一个返回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_pair以及std::pair构造函数本身需要两个对象并尝试制作它们的内部副本。这导致它尝试并调用复制构造函数。但在我的示例中,我希望能够将>新对移动到res,并确保不会制作副本。我认为除非std::pair本身在内部定义了以下构造函数,否则这是不可能的:

pair(T1&& t1, T2&& t2) : first(std::move(t1)), second(std::move(t2))

但它没有,至少在我使用的编译器上没有(gcc 4.3.2)。可能是我的编译器只是过时了,而实际上的新版本会有这个移动感知的构造函数。但是我对移动语义的理解目前有点不稳定,所以我不确定我是否只是在这里忽略了一些东西。那么,我是否正在努力实现,而不是实际重新实现std::pair?或者我的编译器是否过时了?

2 个答案:

答案 0 :(得分:18)

但这不是将被调用的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 d,否则会被复制。以下应该有效:

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

答案 1 :(得分: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])