Возврат std :: function без создания копии - PullRequest
2 голосов
/ 19 марта 2020

При возврате std::function из вызова функции, будет ли возвращенная функция копией определения функции или это ссылка на функцию?

Справочная информация: я хочу избежать bottle шеи в какой-то более или менее чувствительной к производительности части моего приложения. Таким образом, я хочу избежать выделений и копий там, где это не требуется.

Пример кода:

typedef std::function<std::unique_ptr<ControllerResponse>(
    const std::vector<std::string> &pathComponents,
    const std::string &data,
    const std::unordered_map<std::string, std::string> &params)
> ControllerMethod;

ControllerMethod RouteIndex::findRoute(
    const std::vector<std::string> &pathComponents,
    const std::string &method,
    std::map<std::string, std::string> &requestParams) {
   // ... snip
   // suppose globalMap is a class member
   return globalMap.InstanceOfControllerMethod;
}

Будет ли findRoute() возвращать копию или std::function сама по себе просто ссылка?

Ответы [ 2 ]

1 голос
/ 19 марта 2020

C ++ стандарт имеет это сказать о std::function конструкторе копирования:

function(const function& f);

Броски: не выбрасывать исключения, если цель f является специализацией reference_wrapper или указатель на функцию. В противном случае может выдать bad_alloc или любое исключение, выданное конструктором копирования сохраненного вызываемого объекта. [Примечание: реализациям рекомендуется избегать использования динамически выделяемой памяти для небольших вызываемых объектов, например, где цель f - это объект, содержащий только указатель или ссылку на объект и указатель на функцию-член. - конец заметки]

Обязательно прочитайте заметку. Если вы оставите ваши обратные вызовы маленькими, вы сможете копировать std::function без выполнения динамического выделения c.

Так что в вашем примере, если InstanceOfControllerMethod является указателем на функцию, возвращающая копия не должна выделять Память. Но если вы хотите поместить в него указатель на функцию-член, вам следует вместо этого использовать лямбду, так как указатели на функции-члены в C ++ во многих отношениях ломаются и, вероятно, слишком велики для того, чтобы поместиться в std::function:

std::function<void()> get_member_function(A *p)
{
    return [p]() { p->function(); };
}

Поскольку такая лямбда содержит только указатель p, он гарантированно помещается в экземпляр std::function, в отличие от указателя функции-члена, который может принимать 2 и более указателей.

0 голосов
/ 19 марта 2020

Вы возвращаете копию std::function, которая является классом, а не ссылкой.

...