• Какие ЯП (Язык программирования) лучше для написания ядра операционной cистемы?

    @majstar_Zubr
    C++, C#, gamedev
    Недавно узнал об интересной альтернативе - forth. Интересным моментом является такой факт, что в принципе язык можно сразу использовать вместо командой оболочки для ОС. Но это просто для поиграться и повелосипедить, если что-то практическое, то это C, C++ и ... всё остальное, что компилируется (в довесок ко всему смотрите LLVM frontend list)

    В принципе, почему Си хватает - да потому что железо в отношении к ОС выступает часто в виде конечных автоматов, что как бы жёстко связывает руки писать в рамках стуктурно-ориентированного кода. ООП просто не нужно, и если язык был спроектирован под разработку прикладных программ, то там слишком много бесполезного с точки решения задачи написания ОС. Учитывая простую модель памяти Си, очень легко контролировать состояние кэшей всех уровней, а учитывая десятки тысяч часов, вложенных в gcc, писать что-то практическое, кроме как на assembler, толку нет (см. KolibriOS).

    Исходите из того, какой контекст исполнения для вашей ОС вам интересен - если это не железо, то может быть какая-то виртуальная машина.

    Хотя, если исходить из совсем практических соображений, то лучше не писать ОС, а написать несколько модулей ядра для Linux.
    Ответ написан
  • Почему кнопка работает со 2 раза?

    @majstar_Zubr
    C++, C#, gamedev
    На местах строк "bol = false;" "bol = true;" должно быть "bol = !bol;"
    Ответ написан
  • Как действительно поможет ООП в реальной программе?

    @majstar_Zubr
    C++, C#, gamedev
    ООП не про локаничный код, а про упрощение внесения изменений, т.к. все области изменений в текстовом виде локализованы в классах, пространствах имён, модулях. Области изменений непосредственно связаны с абстракциями, и чем грамотнее абстракции сформированы, тем быстрее и проще рефакторить код. В общем случае, под абстракциями понимаются не только модели и сущности, которые относятся к задаче, но и связанные с ними процессы,
    Ответ написан
    Комментировать
  • Стоит ли читать Брюса Эккеля Философия С++?

    @majstar_Zubr
    C++, C#, gamedev
    Да.
    Ответ написан
    Комментировать
  • Как заставить код выполниться лишь раз в почти бесконечном цикле?

    @majstar_Zubr
    C++, C#, gamedev
    void do_one_time() {
         static bool was_called;
         if (!was_called) {
              // ... полезный код
         }
         was_called = true;
    }
    Ответ написан
    Комментировать
  • Как сделать контролируемые обмены в онлайн-игре?

    @majstar_Zubr
    C++, C#, gamedev
    Можно сделать простую машину состояний, для каждого игрока, которая при обмене будет менять состояние с более жадного на более щедрое.

    Состояния будут содержать в себе коэффициенты для стратегий наполнения буферного пула вещей-кандидатов для обмена, из которых будет рандомно выбираться итоговая вещь.

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

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

    @majstar_Zubr
    C++, C#, gamedev
    Любая абстракция может частично или полностью включать определение другой абстракции.

    Есть какие-то сущности.

    Они взаимодействуют в какой-то среде определённым образом.

    Отразим эти правила в какой-то спецификации.

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

    Это удобно, т.к. если мы увеличиваем количество сущностей, у нас все равно получается без проблем описать все взаимодействия.

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

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

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

    Вариант второй: мы не можем сделать композит, потому что на самом деле нам не хватает понятий в спецификации. Нам требуется такая сущность, которая бы в одном случае могла стать одной абстракцией, а в другом случае - другой. Либо нам требуется частичное поведение из разных сущностей. Нам это важно, потому что мы описываем взаимодействия через конечный набор терминов, которые означают абстракции, которые до постановки этой задачи целиком и полностью были синонимами сущностей. Теперь же, для решения нашей задачи придется ввести промежуточный слой отображения между сущностями с одной стороны и понятиями (абстракциями) с другой. В целом, нам придется придумать и описать не только новую сущность, но новую абстракцию.
    Когда мы начнем описывать новую сущность, мы можем прийти к выводу, что нам не хватает терминов, что полет привести к тому, что мы начнем делать ещё один уровень описания, более низкий, мы начнем декомпозировать наши сущности на наборы более низких по уровню абстракций и описывать уже взаимодействия для низкоуровневых абстракций, чтобы произвести обобщения, сформировать низкоуровневых, относительно исходных сушностей терминологию, чтобы суметь сделать такой композит, которые был бы на одном уровне абстракций с исходными сущностями. В целом, это условно плохой вариант, потому что в этом случае инкапсуляция сущности протекла, и нам пришлось нырнуть на уровень абстракции ниже.

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

    Следствие закона такое, что идеальный API и идеальная библиотеке наращиваются только композитами с более высокими абстракциями, никогда не имеют depricated методов, никогда не имеют аналогов и никогда не имеют проблем с обратной совместимостью.
    Ответ написан
  • Что такое экземпляр void?

    @majstar_Zubr
    C++, C#, gamedev
    #include <iostream>
    using namespace std;
    
    int main() {
    	cout << int() << endl;
    	cout << double(78) << endl;
    	
    	cout << bool(-1) << endl;
    	
    	// void r = void();
    	// error: void value not ignored as it ought to be
    	
    	void();
    	void(42);
    	return 0;
    }


    Вывод:
    0
    78
    1

    Это синтаксический сахар, который можно понимать, как конструктор встроенного типа, но фактически это работает, как приведение к типу

    (int)0, (double)76, (bool)-1 соответственно

    и вызова конструктора не происходит.

    Т.е. при компиляции вместо void() произойдет (void)0, результатом будет void. Функция foo возвращает void, потому что это "обратная совместимость" с языком C.
    Ответ написан
  • Как ограничить доступ на изменения к папке с репозиторием git на windows server?

    @majstar_Zubr
    C++, C#, gamedev
    Вам нужно настроить ssh сервер с доступом по ключу, добавить пользователя git, который может только в директории репозитория что-то писать. Все будут подключаться к удалённому репозиторию через ssh.

    Может стать непростой настройка доступа по ключу. Все зависит от того, откуда вы возьмете Openssh: из chocolate, cygwin, по-умолчанию или собственноручно собранный. Дополнительно, некоторые факторы зависят от того, из какого окружения будет использоваться ssh клиент.

    Главное не забывайте, что права на запись в cygwin могут подпортить записи прав на файлы в формате, которые использует Windows (Файл - ПКМ - Свойства - Безопасность). Дополнительно, может не отрабатывать ssh-add (например, в случае, когда клиент из Windiws окружения, а сервер из cygwin), так что возможно придётся использовать приватные ключи, не защищённые мастер-паролем.

    За исключением этих деталей, логика такая же, как в документации
    Ответ написан
  • Как правильно перегрузить конструкторы в классе?

    @majstar_Zubr
    C++, C#, gamedev
    Рассмотрим проблему подробнее.

    class A {
    private:
     int aa;
     int ab;
    
    public:
     A()
         : aa(0), ab(0) {}  // (4) note: candidate constructor not viable: requires
                            // 0 arguments, but 1 was provided
     A(int a)
         : aa(a), ab(0) {}  // (2) note: candidate constructor not viable: no known
                            // conversion from 'A' to 'int' for 1st argument
     A(A& obj);  // (3) note: andidate constructor not viable: expects an l-value
                 // for 1st argument
     void Show() { cout << "Var1: " << aa << endl << "Var2: " << ab << endl; }
    };
    
    int main() {
     A obj = 5;  // (1) error: cannot bind non-const lvalue reference of type ‘A&’
                 // to an rvalue of type ‘A’
     obj.Show();
    
     return 0;
    }


    Стандарт обязывает понимать

    A(A& obj);

    как user-defined конструктор копирования. Поэтому, конструктор копирования T::T(const T&) не будет объявлен по-умолчанию компилятором. Со стандарта C++11 предоставляется возможность заставить компилятор генерировать неявно-объявленный конструктор копирования ключевым словом default

    A(A& obj) = default;

    Неявно объявленный конструктор копирования по-умолчанию имеет сигнатуру T::T(const T&) но лишь в случае, когда все базовые классы T имеют конструкторы копирования с параметрами const B& или const volatile B&, и когда все не статические данные-члены класса T имеют конструкторы копирования с параметрами const M& или const volatile M&.

    В ином случае, неявно объявленный конструктор копирования имеет сигнатуру

    T::T(T&)

    В данном случае, конструктор копирования A(A& obj) является тривиальным с сигнатурой сгенерированного неявно-определённого конструктора копирования T::T(T&).
    Тривиальное копирование практически аналогично std::memmove

    В строке ошибки компиляции происходит следующее:

    1) оператор = в строке с ошибкой компиляции не является инициализирующим, поскольку литерал 5 является (rvalue, нельзя взять адрес) const int. Для исполнения операции присваивания компилятор сначала конструирует A(5);

    ...
    A(int a) : aa(a), ab(0) {
     cout << "Copy ctor with 1 parameter is called " << endl;
    }
    …
    int main() {
    …


    Вывод:
    Copy ctor with 1 parameter is called
    Var1: 5
    Var2: 0


    2) операция присваивания имеет дело с A obj = A (5):

    Справа от оператора присваивания находится временный rvalue типа class A.
    Данное присваивание является инициализирующим, что делает его эквивалентным A obj(A(5));
    Для данной операции необходим конструктор с сигнатурой T::T(T&&)
    Это - конструктор перемещения, и он в классе A отсутствует, поскольку неявное определение конструктора перемещения в классе требует отсутствия user-defined конструкторов копирования, оператора = копирования, оператора = присваивания, деструктора. В нашем случае, у нас имеется user-defined A(A& obj);

    Учитывая вышесказанное, для исправления ошибки компиляции можно либо удалить строку
    A(A& obj); ,
    что приведёт к неявному определению компилятором тривиальных конструкторов копирования и перемещения, либо добавить ещё в объявление класса A строку
    A(A&& obj);

    С точки зрения стандарта С++11 и выше, можно утверждать, что выражения A(A& obj); и A(A&& obj); соответственно эквивалентны A(A& obj) = default; и A(A&& obj) = default;
    Ответ написан
    5 комментариев
  • Как называется сайт, на котором авторы анализируют книги и выдают только суть и важные момент опуская воду?

    @majstar_Zubr
    C++, C#, gamedev
    Возможно вы говориете про mind maps (интеллект карты, диаграммы связей).

    Но их проще искать по группам в соцсетях, либо mindmap по конкретной книге.
    Ответ написан
    Комментировать
  • Можно ли сделать индексаторы динамической длиный?

    @majstar_Zubr
    C++, C#, gamedev
    class People{
    List<Person> data = new List<Person>();
    ...


    + обработка ошибок
    Ответ написан
    Комментировать
  • Rabbitmq очередь последнего состояния (lvc). Как ее реализовать?

    @majstar_Zubr
    C++, C#, gamedev
    Плагин работает с прямыми привязками, каждому ТС будет соответствовать своя очередь. Поддержание очереди не самая сложная работа для RabbitMQ.

    Если вас устраивают ограничены плагина, можете не рассматривать вариант с СУБД. Но если именно через RabbitMQ, то хранить всё в одной очереди идея не лучшая, ибо будете на каждый чих n проверок делать.

    С двумя очередями уже поинтереснее, когда первая будет буфером, а вторая - с фактической информацией, но нужно делать свой воркер, который читает из буфера и пишет в очередь, обеспечивая уникальные значения. Очередей две, но нагрузка у вас получится будет на воркере, а не кластере RabbitMQ, а из второй очереди клиенты могут читать и искать сообщение с инфо о своём ТС.
    Но фишка RabbitMQ все же в queue/exchanges, делать такое на RabbitMQ не очень хорошо.
    Ответ написан
    Комментировать
  • Аналог Eval из JS в C#?

    @majstar_Zubr
    C++, C#, gamedev
    Ответ написан
    Комментировать
  • Как принудительно запустить программу от имени администратора?

    @majstar_Zubr
    C++, C#, gamedev
    Clickonce

    https://docs.microsoft.com/en-us/visualstudio/depl...

    Файл манифеста:

    https://docs.microsoft.com/en-us/dotnet/csharp/lan...

    Или в VS добавить ресурс - манифест файл - там
    <requestedExecutionLevel level="requireAdministrator" uiAccess="true" />


    Powershell:

    runas /user:"имя_компьютера\имя_уч_зап_админа" "C:\путь\program.exe"
    Ответ написан
    Комментировать
  • Где можно ознакомиться с открытыми проектами по С++?

    @majstar_Zubr
    C++, C#, gamedev
    https://github.com/fffaraz/awesome-cpp

    Рекомендую всё же сначала твердо понять ООП на коде C# или Java, EPPlus библиотеку например, потому что в C++ широко применяется обычные RAII обертки для ресурсов и структурный подход.
    Ответ написан
    4 комментария
  • Пользовательские типы и классы это примерно одно и тоже?

    @majstar_Zubr
    C++, C#, gamedev
    Пользовательский тип в узком смысле это составной тип, реализующий некую абстракцию, у которой нет состояния.

    Класс - просто одна из конструкций языка, которая позволяет выражать идеи в рамках парадигмы ООП.

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

    Разница вот в чем.

    При переходе от процедурной парадигмы к структурной, мы переходим от чтения/записи из памяти к операциями над переменными в некоторых областях видимости. Мы вводим понятие аллокации, инициализации, присваивания, освобождение. Для переменных простых типов эти задачи решаются в компиляторе.

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

    При переходе к ООП, структура неразрывно ассоциируется с некоторой функциональностью и некоторым состоянием. Здесь уже для своего пользовательского типа вручную необходимо описывать конструкцию и деструкцию типа. Некоторые языки второе реализуют через сборщик мусора, но в от в C# есть четкое различение между managed и unmanaged типами, потому что для вторых нужно писать финализатор - технически работающий как деструктор, но как подчеркивает наименование, он им не является, т.к. используется в рантайме сборщиком мусора.

    Процедурная парадигма позволяет управлять последовательностью выполнения подпрограмм с помощью goto. Но рамках этой парадигмы, полпрограммы определены статически. В структурной парадигме и ООП подпрограммы легко формировать динамически с помощью указателей на функции / методы, или прямо с помощью анонимных функций или лямбда-выражений. Так вот, определение этих функций или указателей на них - тоже пользовательские типы.

    Вкратце о вариантах трактовки пользовательского типа.

    Первый вариант: синтаксический псевдоним. В C++ делается с помощью typedef, например size_t.

    Второй вариант: Plain Data Object. В разных языках наименование варируется, но идея уходит корнями в структуру данных plain old data struct из Си, которая представляет просто участок памяти, в котором подряд идут публичные поля простых интегрированных типов. Например stuct plain_coord { int x; int y; }; Вот тут большая разница между классом, реализующим абстракцию "Координата" и POD: если вы в программе используете несколько систем координат, то класс, реализующий абстракцию, должен инкапсулировать все POD и конвертацию этих POD из одной системы координат в другую.

    Третий вариант: указатели. Конкретно, в C++ в качестве пользовательских типов могут быть
    указатели на функцию (пользователь хочет определить часть сигнатуры функции как тип)

    указатели на функцию-член (более узкие требования, когда эта функция принадлежит какой-то иерархии)

    указатели на составной тип (указатель на POD структуру, указатель на класс)

    указатель на член класса

    Четвёртый вариант: если язык поддерживает обобщённое программирование, то в качестве пользовательского типа можно использовать скаляр. Например, std:array имеет статический размер, определяемый на момент компиляции. std::array разных размеров суть разные типы. Хотя по факту, это разные классы, но это один шаблонный класс. Вот здесь как раз важнее представлять что-то как тип с некой функциональностью, а какой именно это класс не так важно, когда итак понятно, что это контейнер с определенным публичным интерфейсом.

    Пятый вариант: наконец-то Object Reference класс. Но обычно, когда говорят о таких классах, их наоборот, категоризируют не как типы, а как реализации абстракций, потому что с течением времени задача уточняется, набор абстракции становится другим и приходится делать рефакторинг. Соответственно, может поменяться и набор классов, и предметная модель. А про типы тут даже и вспоминать нечего: они есть, они разные, вот и всё.

    Остальные варианты: посмотрите в сторону Haskell, erlang. В целом, у разных языков разные требования к свойствам типов и предполагаемым методам использования типов. В основном это зависит от того, какую на какие парадигмы и на какую модель памяти нацелен язык программирования.

    В языках без строгой типизации можно придерживаться некоторых конвенций и реализовать классы и ООП. Некоторые языки регламентируют средства, которые должны обеспечивать интерпретаторы и компиляторы, чтобы программисты не начали сами реализовать явное управление типами с проверками - от этого драматически страдает производительность, особенно когда вместо типов появляются строковые токены.
    Ответ написан
    Комментировать
  • В чем суть процедурного программирования?

    @majstar_Zubr
    C++, C#, gamedev
    alex4answ, процедурный стиль использует только понятия модель памяти, типы, инструкции, программа и подпрограмма.

    Вот и всё. Никаких составных типов. Концепция "состояние" в коде никак не выражается. Держите её если хотите в голове либо в комментариях.

    Никаких сущностей в коде. Держите из в голове или в комментариях.

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

    Но это всё уже вводится в структурном программировании.

    Процедурное программирование вводит модель памяти с понятиями стек и куча. Хотите сделать функцию в процедурной парадигме - вам придется оформить её в виде подпрограммы и вызывать её из другой. Причем понятия линковки нет, вы будете делать это используя адрес в куче, а какие-то данные, типа, аргументы, будете сами на стэк ложить, каждый раз при вызове подпрограммы "функция".
    Ах, да, захотите функцию для сложения двух чисел, придется сделать ctrl-c, ctrl-v и в теле подпрограммы написать сложение двух кусков данных взятых со стека. Для разности - копируете код, в теле меняете инструкции. И так для каждой функции.

    Да, понятия область видимости нет, придется его выражать в коде таким вот образом самостоятельно.

    Ну, и поскольку ОС не даст лезть за пределы одного процесса, подпрограмму придется положить в сорцы выше, чем ваш код.

    А максимум абстрагирования, которое вводит процедурное программирование, это символьное произвольное именование адреса в памяти. Да и вместо типов, скорее, используется смещение байтов для коллекции, которым просто даны имена.

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

    IDE может в качестве статического анализа помочь решать многие вопросы, но проще один раз сделать умный компилятор и перейти к языку, который позволяет абстрагировать. Поначалу было не совсем понятно, какой набор плюшек должен быть вшит в компилятор. Но стечением времени люди родили язык Си.

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

    Т.е. берёте вы современный компилятор / интерпретатор любого языка, пишете решение в один файл, не используете составные типы, а только интегрированные простые (если вы выбрали язык со строгой типизацией), не используете функции, а только операторы, как закончите, смотрите на код - вы решили задачу в рамках процедурной парадигмы.

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

    А вот в языке с полной поддержкой процедурной парадигмы можно делать такие подпрограммы, которые косплеят функции, но возвращают несколько "аргументов", причем пишут прямо в память. Да и в принципе, в процедурной парадигме можно делать свой ABI, нет никаких стандартов, нет правил, ничто не истинно и всё дозволено.
    Ответ написан
    Комментировать
  • Как упростить монотонный код на C#?

    @majstar_Zubr
    C++, C#, gamedev
    См. Макконнелл, Совершенный код, глава 18, Табличные методы.
    Ответ написан
    Комментировать
  • В чем преимущества платных почтовых сервисов перед своим?

    @majstar_Zubr
    C++, C#, gamedev
    Потому что существуют белые списки доверенных почтовых серверов.

    P.S. Крупные компании могут ими обмениваться, а попасть в них можно только через постель (но это не точно)
    Ответ написан
    Комментировать