Основные отличия между классами-значениями и классами-сущностями
Обычно в подобном стиле используют классы, представляющие собой некие сложные ЗНАЧЕНИЯ (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, то будет инициировано копирование.
Следует также отметить, что конструктор и оператор перемещения не генерируются компилятором автоматически, если определены собственные конструктор копий и оператор присвоения соответственно. Если же предполагается тривиальная почленная семантика копирования, то и для перемещения будет автоматически сгенерирована тривиальная реализация перемещения