2016-02-11 4 views
3

std::function, как известно, имеет проблемы с производительностью, так как он может выделять кучи. Допустим, если вы на 100% честны, одно распределение кучи вряд ли будет проблемой в большинстве случаев ... но давайте просто предположим, что распределение кучи нежелательно или запрещено в конкретном сценарии. Может быть, мы делаем несколько миллионов обратных вызовов и не хотим выделять несколько миллионов кучи для этого, что угодно.std :: function лямбда-оптимизация

Итак ... мы хотим избежать распределения кучи.

В статье Efficient Use of Lambda Expressions and std::function доктора Доббса дана рекомендация по оптимизации использования std::function, воспользовавшись оптимизацией небольших объектов, которая рекомендована стандартом и реализована во всех стандартных стандартах.

В статье подробно объясняется, как стандартная библиотека должна копировать функтор, поскольку объект std::function может пережить исходный функтор (хотя вы можете использовать std::ref, если вы уверены, что это не так), что было бы плохой mojo. Кроме того, захваты необходимо скопировать, и вот в чем проблема: точный тип закрытия (или его размер) заранее не известен, поскольку это может быть любой тип закрытия с любым количеством захватов, поэтому необходимо принять компромисс. До определенного размера захваты будут сохранены в хранилище внутри объекта function, а кроме того, он будет динамически распределен. Магазин небольшой, от 12 до 16 байт, поэтому предполагается 64-битная сборка, максимум два указателя (не считая фактического указателя функции).

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

Как это работает? Предположение, сделавшее копирование материала вокруг необходимого в первую очередь, состояло в том, что объект functionможет пережить объем первоначального закрытия. Это означает, конечно, что он также переживает структуру, в которой он содержит ссылку, а также все, что упоминается внутри этой структуры.

Как это должно работать? И так как я не могу понять, как это может работать, есть ли более известный рецепт для решения этой проблемы? (тот, который не ссылается на недопустимые объекты)

ответ

1

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

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

Вот простой test который компилируется, но сбой (проверено на clang в режиме C++ 14.)

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