Петли, функциональный дизайн и эффективность: два вопроса

У меня есть два связанных вопроса, один общий и один конкретный для проекта, над которым я работаю.

  1. Обычно, если у меня есть цикл с большим количеством итераций (миллионы) с некоторыми частями кода, выполняемыми при определенных условиях, лучше (более эффективно) иметь один цикл с несколькими условными операторами или несколькими циклами без них. Например.

пример 1:

while (something())
{
    // some common code
    if (condition_a)
        // some code
    if (condition_b)
        // some code
    // some more common code
}

пример 2:

if (condition_a && condition_b)
{
    while (something())
    {
        // some common and specific code
    }
}
else if (condition_a)
    while (something()) //..
else if (condition_b)
    // Another loop
else //...

Кажется, что пример 2 приведет к более эффективному коду за счет избыточности, потому что условия проверяются только один раз, а не миллион раз. Если общий код огромен или существует много возможных условий, это кажется крайне избыточным.

  1. Теперь к моей конкретной проблеме. У меня есть функция, которая читает точки из файла и вставляет их в структуру данных. Это выглядит примерно так:

    while (reader-> read_point) {// сделать что-нибудь // вставить точку}

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

В идеале я хотел бы использовать указатель на функцию, чтобы заранее определить правильную функцию, однако я не думаю, что это возможно, так как reader является экземпляром класса Reader (если это возможно, каким-то образом это решит все мои проблемы).

В этой ситуации лучше, если у меня есть несколько циклов, которые отличаются только условием, или я должен использовать несколько операторов if, чтобы избежать избыточного кода, например.

for(;;)
{
    if (read_every_point)
        if(!reader->read_point())
            break;
    else if (read_inside_circle)
        if(!reader->read_inside_circle())
            break;
    else if // ...
}

2 ответа

Решение

В идеале я хотел бы использовать указатель на функцию, чтобы заранее определить правильную функцию, однако я не думаю, что это возможно, так как reader является экземпляром класса Reader (если это возможно, каким-то образом это решит все мои проблемы).

Для этого вы можете использовать указатели на функции-члены, предполагая, что все ваши функции чтения имеют одинаковую сигнатуру:

typedef void (Reader::*read_fun_t)();
read_fun_t read_fun = &Reader::read_point;
// or
read_fun_t read_fun = &Reader::read_inside_circle;

...

(reader->*read_fun)();

или если вы не чувствуете себя комфортно с ними, просто создайте свои собственные бесплатные функции, которые обертывают вызовы метода:

void read_point( Reader* reader ){ reader->read_point(); }
void read_inside_circle( Reader* reader ){ reader->read_inside_circle(); }

и вместо этого используйте обычные указатели функций.

Чтобы ответить на ваш конкретный вопрос: время, затрачиваемое на чтение файла, сократит время, затрачиваемое на операции if/else. Напишите что-нибудь более читабельное. Это обычно более эффективно и не оптимизируйте его, пока не докажете, что это узкое место.

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

Другие вопросы по тегам