Концепция семантики перемещения была впервые представлена ​​в C++ 11, что является уникальной концепцией, имеющейся лишь в нескольких языках. Благодаря движущейся семантике создание временных объектов можно было легко оптимизировать, не прибегая к многочисленным уловкам, позволяющим избежать ненужных копий.

Зачем нам нужна семантика перемещения?

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

Прежде чем погрузиться в семантику перемещения, давайте рассмотрим построение и назначение копирования. Понимание семантики копирования — первый шаг к пониманию семантики перемещения.

Когда объект создается с помощью другого объекта, объект должен быть сконструирован, а данные исходного объекта копируются в целевой объект. Этот процесс вызывает конструктор копирования. В приведенном ниже примере кода сначала создается объект «foo», а объект «copy_foo» создается из объекта foo. Вызывается определенный конструктор копирования, и атрибуты объекта foo копируются в объект «copy_foo». Объект «foo» имеет атрибут «bar», который является экземпляром структуры Bar. Экземпляр структуры Bar имеет только один атрибут «val», а конструктор класса Foo создает экземпляр объекта Bar в куче. Изменение значения столбца на «10» влияет на значение объекта copy_foo, как показано во фрагменте кода ниже. Это связано с тем, что конструктор копирования во фрагменте кода выполняет поверхностную, а не глубокую копию. В новый объект Foo копируется только ссылка на объект Bar, а не его данные. Поэтому объекты «foo» и «copy_foo» указывают на один и тот же объект «bar».

Вывод кода приведен ниже. Как мы и ожидали, установив значение bar на 10, изменилось и значение атрибута copy_foo (bar).

На следующей диаграмме операция показана как абстрактное понятие. Конструктор копирования Foo создает псевдоним панели и не копирует объект панели.

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

Когда код выполняется, он печатает «Присвоение копии», поскольку скопированный объект foo создается и затем назначается foo.

Оба объекта («foo», «copy_foo») указывают на один и тот же объект «bar». Следовательно, изменение значения бара исходного объекта влияет на объект «copy_foo». Скопированный объект содержит тот же объект, что и на рисунке 1.

Переместить конструктор и переместить назначение, с другой стороны, сделать глубокую копию. Таким образом, новый объект не имеет общих атрибутов. Каждый атрибут объекта перемещается в новый объект.

Конструктор перемещения вызывается, когда объект инициализируется с помощью rvalue. Фрагмент кода ниже показывает конструктор перемещения класса Foo. Другой атрибут объекта бар перемещен в новый атрибут объекта бар.

Изменение значения атрибута «bar» объекта «foo» не изменит атрибуты «copy_foo». Как видно из приведенного ниже вывода, когда значение bar изменяется на foo, атрибут bar для copy_foo не изменяется.

Точно так же назначение перемещения крадет значение другого объекта. Назначение перемещения показано в приведенных ниже фрагментах кода.

Когда мы запускаем программу, объект copy_foo должен иметь «Cat» в качестве значения атрибута bar. Вывод программы приведен ниже.

Примечание. Контейнеры STL будут использовать конструктор перемещения объекта только в том случае, если он не вызывает исключения. Потому что в случае возникновения исключения при перемещении обрабатываемые данные могут быть потеряны, тогда как в конструкторе копирования оригинал не изменится.

Источники и полезные ссылки