Недавно на isocpp.org была опубликована ссылка на статью Эли Бендерского.
«Идеальная пересылка и универсальные ссылки в C++» .
В этой небольшой статье есть простой ответ на простой вопрос — какие проблемы решить и как использовать ссылки rvalue. Одним из нововведений в C++11, направленных на повышение эффективности программы, является семейство методов emplace для STL-контейнеров.
Например, в std::vector появились метод emplace_back (почти аналог метода push_back) и метод emplace (почти аналог метода вставки).
Вот небольшой пример, показывающий назначение этих новых методов:
Если проследить за вызовами конструкторов и деструкторов класса MyKlass, то во время вызова push_back можно увидеть следующее:class MyKlass { public: MyKlass(int ii_, float ff_) {.
} private: {.
} }; some function { std::vector<MyKlass> v; v.push_back(MyKlass(2, 3.14f)); v.emplace_back(2, 3.14f); }
- Сначала выполняется конструктор временного объекта класса MyKlass.
- Затем для объекта, непосредственно расположенного внутри вектора, вызывается конструктор перемещения (если он определен в MyClass, если не определен, то вызывается конструктор копирования)
- Деструктор временных объектов
Поэтому нет смысла создавать и уничтожать временный объект. Почему бы в таком случае не создать объект сразу внутри вектора? Именно это и делает метод emplace_back. Для примера выражения v.emplace_back(2, 3.14f) будет выполнен только один конструктор, создающий объект внутри вектора.
Никакого использования временных объектов.
emplace_back сам вызывает конструктор MyKlass и передает ему необходимые аргументы.
Такое поведение стало возможным благодаря двум нововведениям C++11: вариативным шаблонам и идеальной пересылке.
В этой статье я хочу объяснить, как работает идеальное снаряжение и как его использовать.
Проблема идеальной передачи
Допустим, есть некоторая функция func, принимающая параметры типов E1, E2, ., En. Нам нужно создать функцию-обертку, которая принимает тот же набор параметров.
Другими словами, определить функцию, которая будет передавать полученные параметры другой функции без создания временных переменных, то есть она будет выполнять идеальную передачу.
Для уточнения задачи рассмотрим метод emplace_back, который был описан выше.
Vector::emplace_back передает свои параметры конструктору T, ничего не зная о том, что такое T. Следующий шаг — рассмотреть несколько примеров, показывающих, как можно добиться аналогичного поведения без использования нововведений C++11. Для простоты мы не будем учитывать необходимость использования шаблонов с переменным количеством параметров-аргументов; мы будем считать, что необходимо передать только два аргумента.
Первый вариант, который приходит на ум: template <typename T1, typename T2>
void wrapper(T1 e1, T2 e2) {
func(e1, e2);
}
Но это, очевидно, не будет работать должным образом, если func принимает параметры по ссылке, поскольку оболочка принимает параметры по значению.
При этом, если func изменит параметры, полученные по ссылке, это не повлияет на параметры, передаваемые в обертку (копии, созданные внутри обертки, будут изменены).
Хорошо, тогда можно переделать обертку, чтобы она принимала параметры по ссылке.
Это не будет проблемой, если func принимает данные по значению, а не по ссылке, поскольку func внутри оболочки создаст необходимые копии самой себя.
template <typename T1, typename T2>
void wrapper(T1& e1, T2& e2) {
func(e1, e2);
}
Здесь есть еще одна проблема.
Rvalue не может быть передано в функцию в качестве ссылки.
Таким образом, совершенно тривиальный вызов не скомпилируется: wrapper(42, 3.14f);
Теги: #C++ #c++11 #rvalue #std::forward #C++
-
Новый Подход К Древней Панграмме
19 Oct, 24 -
Проблемы В Сетях. Странное Падение
19 Oct, 24 -
Samsung Тихо Выпустила Телефон Мечты
19 Oct, 24 -
Ардуино На Автомойке
19 Oct, 24