Пытаясь оптимизировать fun_a1()
функция. Переменная j
не меняется в объеме fun_a1()
, Таким образом, проверка j == 1, 2 или 3 для каждой итерации i, очевидно, является пустой тратой циклов ЦП. Но если я пытаюсь вывести оценку состояния за пределы цикла, я должен написать избыточные циклы для каждого условия. В C я могу легко решить эту проблему, используя указатель на функцию. Однако C ++ не позволяет указатели на нестатические функции. Я нашел несколько ссылок, описывающих таинственный «указатель на член». (пример 1, пример 2) Но все еще неясно, как я могу использовать его изнутри самого объекта, например из fun_a ()? Или это может быть оптимизировано другими способами?
class A{
void fun_b(int i);
void fun_c(int i);
void fun_d(int i);
void fun_f(int i);
void fun_a1(int j){
for(int i=0; i<1000; i++){
if(j==1) fun_b(i);
else if(j==2) fun_c(i);
else if(j==3) fun_d(i);
fun_f(i);
}
}void fun_a2(int j){
if(j==1){
for(int i=0; i<1000; i++) {
fun_b(i);
fun_f(i);
}
}
else if(j==2){
for(int i=0; i<1000; i++) {
fun_c(i);
fun_f(i);
}
}
else if(j==3){
for(int i=0; i<1000; i++) {
fun_d(i);
fun_f(i);
}
}
}
};
Использование указателей на функции, если компилятор не удаляет их, является серьезным ударом по производительности.
Необработанная локальная переменная без изменений, вероятно, будет оптимизирована вне цикла: это не очень сложная оптимизация.
Однако, если вы хотите сделать это явным, ответ не является указателем на функцию или метод. Это лямбды и функторы.
template<typename Functor>
void fun_a2_internal(Functor f) {
for(int i = 0; i < 1000; ++i) {
f(i);
}
}
void fun_a2(int j) {
if (j==1)
fun_a2_internal([&](int i){ fun_b(i); fun_f(i); });
else if (j==2)
fun_a2_internal([&](int i){ fun_c(i); fun_f(i); });
else if (j==3)
fun_a2_internal([&](int i){ fun_d(i); fun_f(i); });
}
здесь мы пишем fun_a2_internal
чья работа состоит в том, чтобы сделать цикл и выполнить некоторую задачу в цикле.
наш fun_a2
передает эту задачу в качестве функтора через лямбду.
Это приводит к тому, что компилятор узнает подробности тела цикла при компиляции цикла, потому что функтор operator()
является не виртуальным, и, следовательно, одинаковым для каждого экземпляра.
В общем, если ваш ответ на проблему оптимизации — «использовать указатели на функции» (или указатели на элементы), у вас неправильный ответ.
Вот почему C ++ std::sort
быстрее чем С qsort
,
Вот как бы вы использовали указатель на функцию-член:
void (A::*fun)(int);
if(j == 1) fun = &A::fun_b;
else if(j == 2) fun = &A::fun_c;
else if(j == 3) fun = &A::fun_d;
for(int i=0; i<1000; i++) {
(this->*fun)(i);
fun_f(i);
}
«Оптимизировать» является расплывчатым и никогда не должен спрашивать
1, существует определенная проблема, о которой говорит профессор, основываясь на концепциях
эффективности покрыты
2, есть особая оптимизация, которая должна быть сделана.
То, что вы спрашиваете, это оптимизировать это «переключение» заявление
Да, оператор switch более понятен для этой ситуации, но более эффективный способ сделать это состоит в том, чтобы создать массив указателей на функции, чтобы аннулировать функции, содержащие эти циклы, а затем выполнить
doFunction[j]();
например
typedef void (*myfunc)(void);
myfunc options[10];
main()
{
options[0] = (void*)loop1;
options[1] = (void*)loop2;
options[2] = (void*)loop3;
options[3] = (void*)loop4;
}
PS: i ++ медленнее, чем ++ i, если не оптимизирован компилятором.