LINUX.ORG.RU

Как лучше передать функцию: по указателю или ссылке? (C++)

 


0

4

В Си принято передавать функции по указателю.

Но в С++ есть способ передачи аргументов по ссылке.

Вариант 1:

#include <iostream>

double f(double x)
{
   return x*x;
}

double integration(double (*func)(double),double a, double b, int n)
{

double deltaX = (b-a)/n;

double S = 0.0;

for(int i = 0; i < n; i++)
{
   xi = a + i*deltaX;

   S = S + (*func)(xi + deltaX/2.0);
}

return deltaX*S;
}


int main()
{
  cout << integration(&f,1.0,4.0,50) << endl;
}

Вариант 2:

#include <iostream>

double f(double x)
{
   return x*x;
}

double integration(double (&func)(double),double a, double b, int n)
{

double deltaX = (b-a)/n;

double S = 0.0;

for(int i = 0; i < n; i++)
{
   xi = a + i*deltaX;

   S = S + func(xi + deltaX/2.0);
}

return deltaX*S;
}


int main()
{
  cout << integration(f,1.0,4.0,50) << endl;
}

Но все-таки, какой вариант более правильный в С++?

Deleted
Ответ на: комментарий от Deleted

По правилам языка можно и так, и так.

Deleted
()

S = S + (*func)(xi + deltaX/2.0);

В С++ не обязательно разыменовывать указатель на функцию перед вызовом. Так как такие сущности как функция и указатель на функцию эквивалентны. Такой код у меня работает корректно

int add(int a, int b) {
    return a + b;
}

int main()
{
  int(*f)(int,int) = &add;
  std::cout << f(2,3);
}

Aswed ★★★★★
()
Последнее исправление: Aswed (всего исправлений: 1)

Но все-таки, какой вариант более правильный в С++?

Ни один из предложенных. Тебе нужна std::function.

UVV ★★★★★
()

зри в objdump - ответ найдешь ты там

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

anonymous
()

Лучше в виде ссылки. Она не может быть NULL и это может позволить компилятору что-нибудь соптимизировать.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Лучше в виде ссылки

правильно

Она не может быть NULL

неправильно

int f(int &a) {..}

int m() {int *p= 0; f(*p)}

это может позволить компилятору что-нибудь соптимизировать

зависит от компилятора

anonymous
()

В Си принято передавать функции по указателю.

1) передают не фую по указателю, а указатель на фую; 2) в с кроме указателя на фую ничего больше не передашь

anonymous
()

Вот такой:

template<class F>
double integration(F&& f,double a, double b, int n)

Это позволит передать в функцию лямбду или функтор, а также позволяет компилятору заинлайнить вызов.

slovazap ★★★★★
()

Писать везде (*func) ни разу не удобно, так что лучше по ссылке.

hotpil ★★★★
()
Ответ на: комментарий от Aswed

такие сущности как функция и указатель на функцию эквивалентны

Ага, всего лишь типы у них разные.

anonymous
()
Ответ на: комментарий от ksv

Можно ещё 2005-го года сообщение откопать. Там ниже выложено сообщение, что даже на волосатом шланге разницы практически нет.

UVV ★★★★★
()

Всё крайне просто - если отсутсвие значения входит в одз, используется указатель и его нулевое значение, во всех остальных случаях используется ссылка.

В случае функции, это всё равно будет ссылка на указатель, так что хоть в лоб, хоть по лбу по большому счёту.

onhydro
()
Ответ на: комментарий от UVV

Вот несколько поновее: https://stackoverflow.com/questions/25985248/speed-of-bound-lambda-via-stdfun...

Вы, конечно, опять можете возразить что ответы 2015 года, столько воды утекло, компиляторы уже в десять раз умнее, проблем нет. Советую провести замеры самостоятельно - благо все коды привидены.

Хочу отметить только что std::function стирает всю информацию о вызываемом объекте. Соответственно, у компилятора отсутствует возможность заинлайнить вызов, провести оптимизации. При использовании метода с шаблонами компилятор очень часто может провести существенные оптимизации.

Ну и обычно реализация std::function подразумевает использование виртуальных функций, что добавляет накладные расходы во время исполнения.

ksv
()
Последнее исправление: ksv (всего исправлений: 1)
Ответ на: комментарий от ksv

Ну и обычно реализация std::function подразумевает использование виртуальных функций, что добавляет накладные расходы во время исполнения.

Ололо, клуб любителей посчитать асмовые инструкции.

UVV ★★★★★
()
Ответ на: комментарий от UVV

Ещё раз, медленно, с расстановкой. Можно использовать шаблоны, std::function, указатели на функции.

template<typename C> double integration1(C&& func,double a, double b, int n);
double integration2(std::function<double(double)> func,double a, double b, int n);
double integration3(double (*func)(double),double a, double b, int n);

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

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

std::function не даёт компилятору провести оптимизации, заинлайнить лямбду. В случае медленных функций это не имеет значения. В случае если сами функции очень быстрые, при этом integration вызывается часто - накладные расходы будут существенны (по ссылке вызов через std::function в три раза медленнее).

При использовании шаблонов несколько замедляется время компиляции. Кроме того, на каждую функцию будет сгенерирован свой собственный вариант функции integration1. Про другие недостатки я не слышал (буду раз узнать, если вы располагаете такой информацией).

Собственно, вопрос. Какие ваши аргументы за использование std::function?

ksv
()
Последнее исправление: ksv (всего исправлений: 1)
Ответ на: комментарий от ksv

Вариант с шаблонами тоже норм. Ничего против него не имею. Я был против варианта с голым указателем на функцию.

UVV ★★★★★
()

Как std::function.

invy ★★★★★
()
Ответ на: комментарий от onhydro

Всё крайне просто - если отсутсвие значения входит в одз

Следует использовать std::optional.

robus ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.