23

假设您想利用移动语义,但您的一个可移动类需要是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?还是我的编译器刚刚过时?

4

2 回答 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)

但是,您的示例应该失败,因为 in std::make_pair(f, 10);,f是一个左值并且需要显式moved,否则它会被复制。以下应该有效:

std::pair<Foo, int> res = std::make_pair(std::move(f), 10);
于 2010-11-04T14:26:32.440 回答
2

GCC 4.3.2 不能有完整的实现。对(和元组)应具有移动构造函数:

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])

于 2010-11-04T14:29:34.123 回答