Занимательная задачка: однократный вызов

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Есть некая функция. Она состоит из двух участков кода CodeA и CodeB, которые никак не связаны друг с другом общими переменным и не требуют никаких дополнительных параметров.

Код: Выделить всё

void Function()
{
   <CodeA>
   <CodeB> 
}
Функция вызывается из нескольких мест программы.

После изменений требований клиентами, архитектор создал таску на изменение кода - участок CodeA отныне должен отрабатывать только при первом вызове функции.

Таску просмотрели два программиста. Один С-шник, второй С++-ник. С-шник сразу сразу выдал решение:

Код: Выделить всё

void Function()
{
   static int isFirstCall = 1;
   if (isFirstCall)
   {
      <CodeA>
      isFirstCall = 0;
   }
   <CodeB>
}
С++-ник подумал, и сказал своему коллеге: "Не лезь ты со своим С в наш код". А потом добавил: "Я смогу реализовать новые требования и без условия с проверкой статического флажка".

Указать наиболее простое решение, которое могло быть предложено С++ программистом. Использовать С++ версии 03 (без 11-го стандарта).
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Код: Выделить всё

class A
{
 A ()
 {
  <CodeA>
 };
};
void Function()
{
   static A a;
   <CodeB>
}
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Верное направление. Господа, кто хочет прокомментировать предложенное решение? Что бы вы поменяли здесь и из каких соображений?
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Раз все молчат, пишу окончательное решение. Сионист выбрал верный подход, однако в его решении три проблемы:

1. Код не скомпилируется, так как конструктор расположен в приватной секции класса;
2. Нарушена инкапсуляция функции. До этого CodeA никак нельзя было вызвать отдельно. В новом же варианте кто угодно сможет создать класс A, таким образом вызвав CodeA;
3. Ну и ещё одна косметическая правка - имя класса. Всё-таки имя A не для коммерческого кода.

Код: Выделить всё

void Function()
{
   class CCaller
   {
   public:
      CCaller()
      {
         <CodeA>
      }
   };

   static CCaller singleCall;

   <CodeB>
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Ну и ещё одна косметическая правка - имя класса. Всё-таки имя A не для коммерческого кода.
Это же только пример.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

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

Код: Выделить всё

void Function();

class CCaller
{
    CCaller()
    {
        <Code A>
    }

    friend void Function();
};

void Function()
{
    static CCaller singleCall;

    <Code B>
}

Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Если класс спрятан внутри функции, его уже никто не увидит снаружи, и тем более не вызовет. Это более строгое ограничение, чем приватный конструктор внешнего класса.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Код: Выделить всё

void Function()
{
	static std::vector<int> v(1);
	try
	{
		v.at(0);
		v.clear();

		<Code A>
	}
	catch(std: :o ut_of_range& ex)
	{
	}

    <Code B>
}
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Не одобряю головоломные и неочевидные решения. А так же крайне негативно отношусь к построению программной логики на обработке исключений. Исключения должны использовать только для обработки ошибок!

Но в качестве "а посмотрите как круто можно извернуться" - это, бесспорно, очень занимательный вариант :)
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Кстати, если уж пошла такая пьянка, ещё одно решение. Класса нет, но зато используется C++11, который в первоначальном условии был запрещён.

Код: Выделить всё

void Function()
{
   static int fake = []() -> int
   {
      <CodeA>
      return 0;
   }();

   <CodeB>
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить