2013-07-13 4 views
17

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

+2

+1 для чтения Эффективный C++ – Borgleader

+0

Функциональные объекты редко должны иметь большие накладные расходы. – chris

+0

По крайней мере, это более логично (все объекты, в общем) теперь, когда есть семантика перемещения. –

ответ

18

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

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

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

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

+0

Спасибо за ваше объяснение, а часть «встроенная оптимизация» впечатляет меня. – JavaBeta

+1

Мой опыт работы показывает, что широкое использование 'boost :: bind' приводит к функциям объектов, которые дорого копировать. Он, по-видимому, увеличивается экспоненциально по глубине связывания (привязка обратного вызова, который имеет связанный обратный вызов внутри и т. Д.) –

1

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

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

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

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

+0

Эффективная серия Meyers очень популярна в Китае :-). Кроме того, спасибо за объяснение различия между std :: sort и std :: qsort. – JavaBeta

4

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

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

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

Смежные вопросы