Семантика перемещения - в чем дело? [дубликат]
Возможные Дубликаты:
может кто-нибудь объяснить мне семантику перемещения?
может ли кто-нибудь указать мне на хороший источник или объяснить его здесь, какова семантика перемещения?
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.