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

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

Добавлено: 25 ноя 2015, 16:55
Romeo
Нет, всё-таки не аналогичен. У меня не было флажка вообще.

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

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

   static CCaller singleCall;

   <CodeB>
}
Если же выбирать из твоих двух вариантов, то однозначно следует выбирать второй. Я не знаю, какие там могут возникать подводные камни с внешними static, да и на студию я никогда не равнялся. А вот то, что в первом варианте нарушается инкапсуляция исходной функции - это серьёзный аргумент в пользу отказа от этого варианта.

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

Добавлено: 25 ноя 2015, 17:42
Din666
В целом интересная задачка, спасибо, даже есть над чем посмотрить.!!

Поэтому по варианту кода в конструкторе:
0. СВОЙ второй вариант написал ради прикола.
1. считаю выполнение большого кода в конструкторе злом, в данном случае больше похоже на костыль, чем на красивое решение
2. если можно вынести часть кода (А) из огромной ф-ции - то это наоборот хорошо,
заместо того чтобы городить там еще дополнительные классы/структуры, ограниченные по ф-циональности (например шаблонный класс так нельзя).
А Проблему инкапсуляции можно решить другими средствами, первое что приходит в голову friend.

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

Добавлено: 26 ноя 2015, 12:37
Romeo
Я не понимаю, чем конструктор хуже, чем любой другой метод класса. Если есть веские аргументы в пользу его "худшести", а так же в пользу того, что размещение там большого куска кода вообще является "костылём", предлагаю их высказать. Лично я таких аргументов не имею.

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

Ну и если уж речь зашла о friend, то, как по мне, именно этот квалификатор (а не большой код в конструкторе) является "костылём". Я всегда считал, что использование friend в проекте сигнализирует о том, что иерархия классов плохо продумана, и перепроектировка классов с целью убрать использование данного клалификатора лишь улучшает инкапсуляцию (на этот раз классовую). Единственный случай, когда использование friend оправдано - это при объявление операторов ">>" и "<<" для своего класса. Да и то лишь потому, что подобную архитектуру навязывает стандартная библиотека. Будь на то моя воля, я бы и это исправил, но, к сожалению, править стандарт у меня возможности не имеется :)

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

Добавлено: 26 ноя 2015, 14:20
Din666
1.например: использование класса с тяжелым конструктором в другом, критичном по скорости/памяти, участке кода.
2.например: ловить исключения вызванные из конструктора не всегда, но иногда, требуют плясок с бубном.

Да насчет friend тупанул. и правда годится для быстрого/срочного исправления и так кривого (неправильно спроектированного) кода.
имел ввиду static ф-цию, которую невидно снаружи.
file.cpp: static void func() {}

и позволю повториться:
- если можно вынести часть кода (А) из огромной ф-ции - то это наоборот хорошо

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

Добавлено: 26 ноя 2015, 15:02
Absurd
Din666 писал(а):считаю выполнение большого кода в конструкторе злом
Это интуитивное предубеждение, которое не поддается строгому доказательству. Тем более что у объекта который он конструирует нет никакого состояния, и поэтому он не может сломаться.
Din666 писал(а):в данном случае больше похоже на костыль, чем на красивое решение
Красивого решения тут нет. Хорошая функция должна вести себя одинаково для одних и тех же аргументов. С другой стороны, переносить инициализацию статических данных на клиента тоже некомильфо. Он не будет разбираться в тонкостях.

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

Добавлено: 26 ноя 2015, 15:20
Romeo
Din666 писал(а): 1.например: использование класса с тяжелым конструктором в другом, критичном по скорости/памяти, участке кода.
2.например: ловить исключения вызванные из конструктора не всегда, но иногда, требуют плясок с бубном.
Ни первое, ни второе для нашего класса не актуально. Конструктор максимально прост, он не бросает никаких исключений, и класс никто больше не использует в качестве агрегата. Так что никак костылей :)

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

Добавлено: 27 ноя 2015, 13:47
Din666
ладна, ладна, сдаюсь )))

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

Добавлено: 27 ноя 2015, 14:46
Romeo
Din666, если уж ты добрался до одной занимательной задачки, может и до второй доберёшься? А то народу, то ли лень решать, то ли боятся впросак попасть :)

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

Добавлено: 28 ноя 2015, 15:34
WinMain
Вот как эту задачку можно решить средствами Windows API без использования статических объектов С++

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

void Function()
{
	_TCHAR* szAtomName = _T("SingleCallCode");
	if (!::FindAtom(szAtomName))
	{
		::AddAtom(szAtomName);

		<Code A>
	}

	<Code B>
}

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

Добавлено: 28 ноя 2015, 17:21
Absurd
WinMain писал(а):Вот как эту задачку можно решить средствами Windows API без использования статических объектов С++

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

	if (!::FindAtom(szAtomName))
	{
		::AddAtom(szAtomName);
	}
Это не атомарная операция. Два и более тредов могут одновременно не найти атом. Тут надо std::atomic_flag использовать.

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

namespace {
  std::atomic_flag guard = ATOMIC_FLAG_INIT;
}

void Function()
{
  if (!guard.test_and_set(std::memory_order_acquire))
  {
     doOnce();
  }
  doAlways();
}