Использование семантики перемещения с std :: pair или std :: tuple - PullRequest
19 голосов
/ 04 ноября 2010

Предположим, вы хотите воспользоваться семантикой перемещения, но один из ваших подвижных классов должен быть частью 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 ]

19 голосов
/ 04 ноября 2010

Это не тот конструктор 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 является lvalue и должно быть явно move dв противном случае оно копируется.Должно работать следующее:

std::pair<Foo, int> res = std::make_pair(std::move(f), 10);
2 голосов
/ 04 ноября 2010

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)

...