Петли, функциональный дизайн и эффективность: два вопроса
У меня есть два связанных вопроса, один общий и один конкретный для проекта, над которым я работаю.
- Обычно, если у меня есть цикл с большим количеством итераций (миллионы) с некоторыми частями кода, выполняемыми при определенных условиях, лучше (более эффективно) иметь один цикл с несколькими условными операторами или несколькими циклами без них. Например.
пример 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 приведет к более эффективному коду за счет избыточности, потому что условия проверяются только один раз, а не миллион раз. Если общий код огромен или существует много возможных условий, это кажется крайне избыточным.
Теперь к моей конкретной проблеме. У меня есть функция, которая читает точки из файла и вставляет их в структуру данных. Это выглядит примерно так:
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. Напишите что-нибудь более читабельное. Это обычно более эффективно и не оптимизируйте его, пока не докажете, что это узкое место.
Чтобы ответить на ваш общий вопрос: это зависит от многих вещей, и современные компиляторы очень хорошо справляются с задачей независимо от вашей интуиции. Так что это теоретическое обсуждение, пока у вас не будет рабочего кода на конкретном компиляторе и архитектуре.