Концепция семантики перемещения была впервые представлена в 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 будут использовать конструктор перемещения объекта только в том случае, если он не вызывает исключения. Потому что в случае возникновения исключения при перемещении обрабатываемые данные могут быть потеряны, тогда как в конструкторе копирования оригинал не изменится.
Источники и полезные ссылки
- Мелкое и глубокое копирование: https://www.learncpp.com/cpp-tutorial/shallow-vs-deep-copying/
- Конструктор копирования: https://www.learncpp.com/cpp-tutorial/the-copy-constructor/
- Инициализация копирования: https://www.learncpp.com/cpp-tutorial/copy-initialization/
- Переместить конструкторы и переместить задание: https://www.learncpp.com/cpp-tutorial/move-constructors-and-move-assignment/