简体   繁体   English

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

[英]Using move semantics with std::pair or std::tuple

Suppose you want to take advantage of move semantics, but one of your movable classes needs to be part of an std::pair . 假设你想利用移动语义,但你的一个可移动类需要成为std::pair The purpose would be to create a function that returns an std::pair that can be treated as an rvalue, and forwarded along. 目的是创建一个函数,该函数返回一个std::pair ,可以将其视为rvalue并转发。

But I can't see how this can be done, unless an internal change to std::pair itself is made, to make it aware of move semantics. 但我无法看到如何做到这一点,除非对std::pair本身进行内部更改,以使其了解移动语义。

Consider the following code: 请考虑以下代码:

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
}

The problem is that std::make_pair , as well as the std::pair constructor itself, takes two objects and tries to make internal copies of them. 问题是std::make_pair以及std::pair构造函数本身需要两个对象并尝试制作它们的内部副本。 This causes it to try and invoke the copy constructor. 这导致它尝试并调用复制构造函数。 But in my example, I want to be able to move the new pair into res , and ensure that no copies are made. 但在我的例子中,我希望能够新对移动res ,并确保不会创建副本。 I would think this wouldn't be possible unless std::pair itself had the following constructor defined internally: 除非std::pair本身在内部定义了以下构造函数,否则我认为这是不可能的:

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

But it doesn't, at least not on the compiler I'm using (gcc 4.3.2). 但它没有,至少在我使用的编译器上没有(gcc 4.3.2)。 It may be that my compiler is simply out-of-date, and newer versions in fact will have this move-aware constructor. 这可能是因为我的编译器是简单地外的日期,而事实上新版本都会有这样举动感知构造。 But my understanding of move semantics is somewhat flaky at the moment, so I'm not sure if I'm simply overlooking something here. 但是我对移动语义的理解目前有点不稳定,所以我不确定我是否只是在这里忽略了一些东西。 So, is what I'm trying to accomplish possible, without actually reimplementing std::pair ? 那么,我是否正在努力实现,而不是实际重新实现std::pair Or is my compiler just out of date? 或者我的编译器是否已过时?

That's not the std::pair constructor that will be called, though. 但是,这不是将被调用的std::pair构造函数。 The std::pair move constructor will be called, and the move constructor should do exactly what you expect (N3126 20.3.5.2/6): 将调用std::pair移动构造函数,移动构造函数应该完全符合您的预期(N3126 20.3.5.2/6):

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

Effects: The constructor initializes first with std::move(p.first) and second with std::move(p.second) . 效果:构造函数首先使用std::move(p.first)初始化,然后使用std::move(p.second)第二次初始化。

However, your example should fail because in std::make_pair(f, 10); 但是,您的示例应该失败,因为在std::make_pair(f, 10); , f is an lvalue and needs to be explicitly move d, otherwise it is copied. f是左值,需要明确move d,否则复制。 The following should work: 以下应该有效:

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

GCC 4.3.2 must not have a complete implementation. GCC 4.3.2必须没有完整的实施。 pair (and tuple) shall have move constructors: pair(和tuple)应该有移动构造函数:

template<class U, class V> pair(U&& x, V&& y);
Effects: The constructor initializes first with std::forward(x) and second with std::forward(y). 效果:构造函数首先使用std :: forward(x)进行初始化,然后使用std :: forward(y)进行第二次初始化。
template<class U, class V> pair(pair<U, V>&& p);
Effects: The constructor initializes first with std::move(p.first) and second with std::move(p.second). 效果:构造函数首先使用std :: move(p.first)进行初始化,然后使用std :: move(p.second)进行第二次初始化。

(From [pairs.pair] in n3126) (来自n3126中的[pairs.pair])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM