Ссылки на цифры с номерами в Sphinx и reStructuredText

Чтобы проиллюстрировать необходимость в семантике перемещения , рассмотрим этот пример без семантики перемещения:

Вот функция, которая берет объект типа T и возвращает объект тот же тип T:

T f(T o) { return o; }
  //^^^ new object constructed

Вышеупомянутая функция использует вызов по значению , что означает, что когда эта функция вызывается, объект должен быть построен для использования этой функцией. Поскольку функция также возвращает значение , для возвращаемого значения создается другой новый объект:

T b = f(a);
  //^ new object constructed

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

Когда новый объект создается из возвращаемого значения, конструктор копирования вызывается в copy содержимое временного объекта для нового объект b. После завершения функции временный объект, используемый в этой функции, выходит из области видимости и уничтожается.


Теперь давайте рассмотрим, что делает конструктор копии .

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

// Copy constructor
T::T(T &old) {
    copy_data(m_a, old.m_a);
    copy_data(m_b, old.m_b);
    copy_data(m_c, old.m_c);
}

С семантикой перемещения теперь можно сделать большую часть этой работы менее неприятной, просто переместить данные, а не копировать.

// Move constructor
T::T(T &&old) noexcept {
    m_a = std::move(old.m_a);
    m_b = std::move(old.m_b);
    m_c = std::move(old.m_c);
}

Перемещение данных предполагает повторное связывание данных с новым объектом , И копия вообще не выполняется .

Это выполняется с помощью ссылки rvalue. Ссылка rvalue очень похожа на ссылку lvalue с одним важным отличием: ссылка rvalue может быть перемещена , а значение lvalue не может быть.

Из cppreference.com :

Чтобы обеспечить надежную гарантию исключения, пользовательские конструкторы перемещения не должны генерировать исключения. На самом деле стандартные контейнеры обычно полагаются на std :: move_if_noexcept, чтобы выбирать между перемещением и копированием, когда элементы контейнера необходимо переместить. Если предусмотрены как конструкторы копирования, так и перемещения, разрешение перегрузки выбирает конструктор перемещения, если аргумент представляет собой rvalue (либо значение praleue, такое как безымянное временное, либо значение x, такое как результат std :: move), и выбирает конструктор копирования, если аргумент - это lvalue (именованный объект или оператор / оператор, возвращающий ссылку lvalue). Если предоставлен только конструктор копирования, все его категории выбирают (до тех пор, пока он принимает ссылку на const, поскольку rvalues ​​может связывать ссылки const), что делает копирование резервной копии для перемещения, когда перемещение недоступно. Во многих ситуациях перемещение конструкторов оптимизируется, даже если они будут производить наблюдаемые побочные эффекты, см. Копирование elision. Конструктор называется «конструктором перемещения», когда он принимает значение rvalue в качестве параметра. Он не обязан ничего перемещать, класс не требует, чтобы ресурс был перемещен, а «конструктор перемещения» не мог перемещать ресурс, как в допустимом (но, возможно, не разумном) случае, когда параметр является const rvalue reference (const T & amp;).

blockquote>

30
задан Chris Morgan 18 July 2011 в 17:13
поделиться