Семантика перемещения - в чем дело? [дубликат]

Возможные Дубликаты:
может кто-нибудь объяснить мне семантику перемещения?

может ли кто-нибудь указать мне на хороший источник или объяснить его здесь, какова семантика перемещения?

4 ответов


забудьте о C++0x на данный момент. Семантика перемещения-это то, что не зависит от языка . C++0x просто предоставляет стандартный способ выполнения операций с семантикой перемещения.

определение

переместить семантика определите поведение определенных операций. Большую часть времени они контрастируют с скопировать семантику, поэтому было бы полезно сначала определить их.

задание копировать семантика имеет следующие характеристики:

// Copy semantics
assert(b == c);
a = b;
assert(a == b && b == c);

то есть a заканчивается равен b, оставить b без изменений.

задание переместить семантика имеет более слабые условия сообщение:

// Move semantics
assert(b == c);
move(a, b); // not C++0x
assert(a == c);

обратите внимание, что больше нет никакой гарантии, что b остается неизменным после назначения с семантикой перемещения. В этом принципиальное отличие.

использует

одно преимущество движения семантика заключается в том, что она позволяет оптимизировать в определенных ситуациях. Рассмотрим следующий тип регулярного значения:

struct A { T* x; };

предположим также, что мы определяем два объекта типа A равным МФЛ их x член указывает на равные значения.

bool operator==(const A& lhs, const A& rhs) { return *lhs.x == *rhs.x; }

наконец, предположим, что мы определяем объект A иметь единоличное владение над указателем их x член.

A::~A() { delete x; }
A::A(const A& rhs) : x(new T(rhs.x)) {}
A& A::operator=(const A& rhs) { if (this != &rhs) *x = *rhs.x; }

теперь предположим, что мы хотим определить функцию для замены двух A объекты.

мы могли бы сделать это обычным способом с семантикой копирования.

void swap(A& a, A& b)
{
    A t = a;
    a = b;
    b = t;
}

однако это излишне неэффективно. Что мы делаем?

  • мы создаем копию a на t.
  • затем мы копируем b на a.
  • скопировать t на b.
  • наконец, уничтожить t.

если T объекты дорого копировать, то это расточительно. Если бы я попросил вас поменять местами два файла на вашем компьютере, вы бы не создали третий файл, а затем скопировать и вставить содержимое файла вокруг, прежде чем уничтожить временный файл, не так ли? Нет, ты бы движение один файл,движение второй в первую позицию, затем, наконец,движение первый файл во второй. Нет необходимости копировать данные.

в нашем случае легко перемещаться по объектам типа A:

// Not C++0x
void move(A& lhs, A& rhs)
{
    lhs.x = rhs.x;
    rhs.x = 0;
}

мы просто двигайтесь rhsуказатель на lhs и затем отказаться rhs владение этим указателем (установив его в значение null). Это должно объяснить, почему более слабое условие post семантики перемещения позволяет оптимизировать.

С этой новой операцией перемещения, мы можем определить оптимизированный своп:

void swap(A& a, A& b)
{
    A t;
    move(t, a);
    move(a, b);
    move(b, t);
}

еще одним преимуществом семантики перемещения является то, что она позволяет перемещать объекты, которые не могут быть скопированы. Ярким примером этого является std::auto_ptr.

C++0x

C++0x позволяет перемещать семантику через ее ссылочную функцию rvalue. В частности, операции такого рода:

a = b;

есть семантика перемещения, когда b является ссылкой rvalue (spelt T&&), в противном случае у них есть семантика копирования. Вы можете заставить семантику перемещения с помощью std::move функция (отличается от move я задал ранее), когда b не rvalue ссылка:

a = std::move(b);

std::move - это простая функция, которая по существу приводит свой аргумент к ссылке rvalue. Следует отметить, что результаты выражений (например, вызов функции) автоматически ссылки rvalue, поэтому вы можете использовать семантику перемещения в этих случаях без изменения кода.

чтобы определить оптимизацию перемещения, необходимо определить конструктор перемещения и оператор назначения перемещения:

T::T(T&&);
T& operator=(T&&);

поскольку эти операции имеют семантику перемещения, вы можете изменять переданные аргументы (при условии вы оставляете объект в разрушаемом состоянии).

вывод

это, по сути, все, что нужно. Обратите внимание, что ссылки rvalue также используются для идеальной пересылки в C++0x (из-за специально созданных системных взаимодействий типов между ссылками rvalue и другими типами), но это не связано с семантикой перемещения, поэтому я не обсуждал это здесь.


в принципе, ссылки rvalue позволяют определять, когда объекты являются временными, и вам не нужно сохранять их внутреннее состояние. Это позволяет гораздо более эффективный код, где C++03 используется для копирования все время, в C++0x вы можете продолжать повторно использовать те же ресурсы. Кроме того, ссылки rvalue обеспечивают идеальную пересылку.

посмотреть ответ.


Я прочитал тонну текстовых объяснений около года и не понял всего о ссылках на r-value пока я не посмотрю эту отличную презентацию Скотта Мейера : http://skillsmatter.com/podcast/home/move-semanticsperfect-forwarding-and-rvalue-references

Он объясняет таким образом, что это смешно и достаточно медленно, чтобы понять все то, что происходит в процессах.

Я знаю, это 1h30, но на самом деле это лучшее объяснение, которое у меня есть был в прошлом году.

после прочтения статей (как и другие ответы), просмотр этого видео расплавил его вместе в моем уме последовательным образом и через несколько дней после того, как я смог объяснить это некоторым коллегам и объяснить, как использовать std::unique_ptr (как это связано - это позволяет только семантику перемещения, а не копировать), потому что это требует понимания std::move (), что требует понимания семантики перемещения.


рад видеть такой вопрос, и я рад поделиться своей точкой зрения. Я думаю, вы спрашиваете об исправлении ошибки в обозначении самого языка C++, а не только другой функции языка C++. "Жучок" существует уже десятки лет. То есть конструктор копирования.

конструкторы копирования кажется очень странным, если вы знаете, в физике есть много вещей, которые не могут быть скопированы, как энергия и масса. Это просто шутка, но на самом деле в мире программирования кроме того, такие объекты, как эксклюзивные файловые дескрипторы, не копируются. Поэтому C++ программисты и дизайнеры придумали некоторые хитрости, чтобы справиться с этим. Есть 3 известных: NRVO,boost::noncopyable и std::auto_ptr.

NRVO (Named Return Value Optimization) - это метод, который позволяет функции возвращать объект по значению без вызова конструктора копирования. Но проблема с NRVO заключается в том, что, хотя конструктор копирования фактически не вызывается, a public объявление конструктора копирования все еще необходимо, что означает, объекты boost::noncopyable не совместим с NRVO.

std::auto_ptr - еще одна пробная версия для обхода конструктора копирования. Возможно, вы видели его "конструктор копирования", реализованный как

template <typename _T>
auto_ptr(auto_ptr<_T>& source)
{
     _ptr = source._ptr; // where _ptr is the pointer to the contained object
     source._ptr = NULL;
}

это вовсе не копия, а "переместить". Вы можете рассматривать такое поведение как прототип переместить семантический.

но std::auto_ptr также имеет свою собственную проблему: он не совместим с контейнерами STL. Так что, к сожалению, ничего о noncopyable больно.

это было болезненно, пока семантика перемещения C++0x, наконец, не будет опубликована и реализована создателями компилятора.

простым способом вы можете просто подумать о семантическом перемещении как о чем-то таком же, как "копирование" поведения std::auto_ptr, но с полной поддержкой языковых функций, поэтому он отлично работает с контейнерами и алгоритмом.

кстати в C++0x std::auto_ptr устарел и новый тип шаблона std::unique_ptr is рекомендуемый.

моя история закончится сейчас. Пожалуйста, обратитесь к другим сообщениям, если вы хотите узнать больше об этом, как странный синтаксис и система rvalue.