Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP_otvety_k_ekzamenu.doc
Скачиваний:
61
Добавлен:
13.04.2015
Размер:
786.94 Кб
Скачать

Оптимизация копирования

Большинство современных компиляторов С++ реализуют необязательную по стандарту языка оптимизацию RVO (Return Value Optimization), чтобы уменьшить число копируемых объектов.

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

Некоторые компиляторы также поддерживают дополнительную более сложную оптимизацию NRVO (Named Return Value Optimization), когда из функции возвращается не временный объект, а обычный локальный объект. Для многих случаев компилятор в состоянии вычислить что именно данный объект будет возвращен вызывающей стороне, и аналогично, вместо создания собственного объекта использует неявно передаваемый адрес возврата.

10. Основные отличия между классами-значениями и классами-сущностями. Запрещение копирования объектов. Основные отличия между классами-значениями и классами-сущностями.

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]