Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

Изменить: Возможно, также стоит упомянуть, что то же самое относится к lambdas, поскольку они действительно просто маскируют объекты функции. Вы не знаете имя класса, но создаете класс в непосредственной близости от области действия, которая перегружает оператор вызова функции, и это то, что вызывается при вызове лямбда. [Спасибо @Mark Garcia.]

Ответ 2

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

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

Другие ответы прекрасно справляются с обоснованием.

Ответ 3

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

"В обоих указателях функций C и С++ передаются значения. Объекты STL-функции моделируются после указателей функций, поэтому соглашение в STL - это то, что объекты функции также передаются по значению при передаче в и из функций."

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

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