Страница 1 из 3

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

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

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

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

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

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

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

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

Указать наиболее простое решение, которое могло быть предложено С++ программистом. Использовать С++ версии 03 (без 11-го стандарта).

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

Добавлено: 07 ноя 2015, 15:37
Сионист

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

class A
{
 A ()
 {
  <CodeA>
 };
};
void Function()
{
   static A a;
   <CodeB>
}

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

Добавлено: 07 ноя 2015, 16:10
Romeo
Верное направление. Господа, кто хочет прокомментировать предложенное решение? Что бы вы поменяли здесь и из каких соображений?

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

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

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

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

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

   static CCaller singleCall;

   <CodeB>
}

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

Добавлено: 09 ноя 2015, 18:55
Сионист
Ну и ещё одна косметическая правка - имя класса. Всё-таки имя A не для коммерческого кода.
Это же только пример.

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

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

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

void Function();

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

    friend void Function();
};

void Function()
{
    static CCaller singleCall;

    <Code B>
}


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

Добавлено: 10 ноя 2015, 15:58
Romeo
Если класс спрятан внутри функции, его уже никто не увидит снаружи, и тем более не вызовет. Это более строгое ограничение, чем приватный конструктор внешнего класса.

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

Добавлено: 11 ноя 2015, 18:09
WinMain

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

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>
}

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

Добавлено: 12 ноя 2015, 11:35
Romeo
Не одобряю головоломные и неочевидные решения. А так же крайне негативно отношусь к построению программной логики на обработке исключений. Исключения должны использовать только для обработки ошибок!

Но в качестве "а посмотрите как круто можно извернуться" - это, бесспорно, очень занимательный вариант :)

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

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

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

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

   <CodeB>
}