почему функциональные объекты должны передаваться по значению

Я только что прочитал классическую книгу «Эффективное C ++, 3-е издание», и в пункте 20 автор приходит к выводу, что встроенные типы, итераторы STL и типы функциональных объектов больше подходят для передачи по значению. Я мог бы хорошо понять причину для встроенных и итераторов типов, но почему объект функции должен передаваться по значению, как мы знаем, это все равно классового типа?

19

Решение

В типичном случае функциональный объект не будет иметь или (чаще всего) не будет постоянного состояния. В таком случае передача по значению может вообще не требовать передачи чего-либо вообще — передаваемое «значение» в основном мало или не более чем заполнитель для «это объект».

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

Компилятор может быть в состоянии сделать то же самое, когда вы вместо этого передаете указатель или ссылку, но это не так просто — гораздо чаще вы получите созданный объект, его адрес переданный, а затем оператор вызова функции для этот объект вызывается через этот указатель.

Редактировать: Вероятно, также стоит упомянуть, что то же самое относится к лямбдам, поскольку они на самом деле являются просто скрытыми функциональными объектами. Вы не знаете имя класса, но они создают класс в непосредственно окружающей области видимости, который перегружает оператор вызова функции, который вызывается, когда вы «вызываете» лямбду. [Спасибо @ Марк Гарсия.]

19

Другие решения

Причина № 1 для передачи функциональных объектов по значению заключается в том, что стандартная библиотека требует, чтобы функциональные объекты, которые вы передаете в ее алгоритмы, были копируемыми. C ++ 11 §25.1 / 10:

[Примечание: если не указано иное, алгоритмам, которые принимают функциональные объекты в качестве аргументов, разрешено копировать
эти функциональные объекты свободно. Программисты, для которых важна идентичность объекта, должны рассмотреть возможность использования
класс-обёртка, который указывает на объект без копирования, такой как reference_wrapper<T> (20.8.3),
или какое-то эквивалентное решение. —Конечная записка]

Другие ответы делают большую работу по объяснению обоснования.

5

Из Effective STL (поскольку вам, похоже, нравится Скотт Мейерс), пункт 38 Классы функторов проектирования для передачи по значению.

«Как в C, так и в C ++ указатели на функции передаются по значению. Объекты функций STL моделируются после указателей на функции, поэтому в STL принято, что объекты функций также передаются по значению при передаче в функции и из функций».

Это имеет некоторые преимущества и некоторые последствия, как сказал @Jerry Coffin, компилятор может сделать некоторые оптимизации, такие как вставка кода, чтобы избежать вызовов функций (вы должны пометить ваш функтор как встроенный). Хорошим примером этого случая является сравнение производительности qsort против std :: sort, где std :: sort, использующий встроенные функторы, значительно превосходит qsort, вы можете найти больше информации об этом в Effective STL, где это подробно обсуждается и упоминается в нескольких главы.

Это также имеет несколько последствий, так как объекты функций передаются и возвращаются по значению, вы должны убедиться, что ваш объект имеет четко определенные механизмы копирования, малы по размеру (в противном случае это может дорого обойтись) и мономорфен (поскольку передается полиморфно объекты по значению могут привести к нарезке объектов).

2
По вопросам рекламы [email protected]