Основные отличия между классами-значениями и классами-сущностями

Обычно в подобном стиле используют классы, представляющие собой некие сложные ЗНАЧЕНИЯ (values), которыми программист манипулирует подобно переменным встроенных типов. Копирование редко применяется для классов, представляющих собой СУЩНОСТИ (entities) реального мира. Для классов-сущностей чаще свойственна передача через функции по ссылке/указателю, а операцию копирования часто в явном виде запрещают. Отличить значения от сущностей довольно просто - для классов-значений (сложные числа, матрицы, физические единицы, деньги, строки, типовые структуры данных), идентичность двух объектов определяется равенством значений всех полей. Для классов-сущностей (люди, заказы, продукты, события) идентичность определяется равенством некоторых отдельных ключевых полей (уникальный номер, идентификатор или адрес), и часто, исходя из логики задачи, в программе одновременно не может существовать копий объектов-сущностей с одинаковыми значениями таких полей.

11. Перемещение объектов. Конструктор перемещения и оператор перемещающего присвоения. Понятие rvalue-ссылки. Функция std::move.

Принятый в 2011г. обновленный стандарт языка С++ вносит полезную дополнительную смежную с копированием функциональность - конструкторы и операторы перемещения (Move constructors, Move assignment operators).

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

С++11 позволяет определить специальные функции-члены, называемые КОНСТРУКТОРАМИ ПЕРЕМЕЩЕНИЯ (move constructors). Такие конструкторы следует определять для перехвата ресурсов из временных объектов вместо избыточного копирования. Как и конструктор копирования, конструктор перемещения принимает единственный аргумент - так называемую, rvalue-ссылку на объект, обозначаемому двумя подряд символами амперсанда. Такая ссылка может быть инициализирована лишь rvalue-объектом, т.е. результатом вычисления выражения, не имеющим постоянного местоположения в памяти, как lvalue:

int x;

int & simpleRefToRValue = x + 2; // Ошибка - обычная ссылка на rvalue

int && rvalueRefToRValue = x + 2; // ОК, rvalue-ссылка на rvalue

Семантика конструктора перемещения предполагает конструирование нового объекта путем перехвата динамически управляемых ресурсов из объекта, который в ближайшее время будет уничтожен (в частности, из временного). Конструктор перемещения для стека может просто инициализировать указатели на блок данных указателями из временного объекта-оригинала. При этом, поскольку объект-оригинал в ближайшее время будет уничтожен, объект-копия как бы “отбирает” у него ресурсы путем их принудительного обнуления в объекте-оригинале. Чтобы обеспечить такую возможность, в отличие от конструкторов копий, конструкторы перемещения предполагают передачу неконстантных rvalue-ссылок.

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

● может быть корректно уничтожен;

● может быть переприсвоен другим копирующим или перемещающим присвоением.

Перемещение может быть явно инициировано при помощи новой встроенной функции std::move:

Int main ()

{

Stack s1;

Stack s2( 20 );

s1 = std::move( s2 );

}

Использование функции std::move также полезно при перемещении составных объектов, дочерние объекты которых имеют собственные конструкторы перемещения

// пример Конструктор перемещения

BigClass ( BigClass && _temporar )

: s( std::move( _copy.s ) ) // Инициируем перемещение явно!

{

}

};

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

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

Наши рекомендации