Ответы пользователя по тегу C++
  • В чем разница int mas[], int mas[0], int mas[100]?

    @Mercury13
    Программист на «си с крестами» и не только
    int mas[] используется в трёх местах.

    1. Когда размер определяется инициализатором: int mas[] = { 1, 2, 3, 4, 5 };
    2. Чтобы задать параметр вида «массив неопределённой длины»: double vecLen(double a[], int size) {}
    Си не может жёстко задавать размер массива в параметре, чтобы больший или меньший не подходил; даже если напишешь напишешь double vecLen(double a[3]) {}, всё равно другой массив подойдёт. Си++ задаёт так: double vecLen(double (&a)[3]) {})
    3. Подсказал jcmvbkbc, реально мало на что нужно: extern int a[].

    int mas[0] создаёт массив нулевой длины, надобности в котором, понятное дело, никакой. Зато этот код используется, чтобы накладывать структуру данных, которая заканчивается массивом неизвестной длины, на какой-то буфер в памяти — как указатель: тут массив (C++ не проверяет выход за границу).

    struct Packet {
      unsigned short length;
      unsigned char data[0];
    }
    
    void processPacket(void* data, unsigned length)
    {
       // Простите уж, что перешёл на C++
       const Packet& packet = *reinterpret_cast<Packet*>(data);
       if (length != sizeof(Packet) + packet.length)
         throw std::logic_error("Packet size mismatch");
       for (unsigned i = 0; i < packet.length; ++i) {}
    }
    Ответ написан
    8 комментариев
  • Как понять заголовочные файлы?

    @Mercury13
    Программист на «си с крестами» и не только
    #include — как ни странно.

    Вы так и не поняли такой вещи, как «единица компиляции». Дело в том, что в Си c-файлы компилируются независимо друг от друга (в единую программу всё собирает линкер). А чтобы сказать «оно есть, только в другой единице компиляции», используют прототипы и extern’ы.

    А если вы хотите просто внести код в ту же единицу компиляции, просто пишите его в хедере, да и всё. Только в большинстве компиляторов это исключает предкомпилированные хедеры — а ТАКИЕ хедеры вам предкомпилировать, скорее всего, и не нужно.

    <брюзга mode on>
    Не создают кода (а значит, в традиционной системе с кучей единиц компиляции находится именно в хедерах)
    • extern и прототипы
    • inline
    • не до конца специфицированные шаблоны
    • static-поля в классе (но потом это static-поле придётся повторить в какой-нибудь одной единице компиляции)
    • может, ещё что-то, только я забыл…
    <брюзга mode off>
    Ответ написан
    1 комментарий
  • Как дополнить топологическую сортировку?

    @Mercury13
    Программист на «си с крестами» и не только
    С двузначными метками посещения (bool used[]) — никак.

    Надо перейти на трёхзначные метки (UNVISITED, PARTLY_VISITED, VISITED).

    void dfs (int v) {
      state[v] = PARTLY_VISITED;
        .....
      state[v] = VISITED;
      ans.push_back (v);
    }


    Неплохой пример есть в вашем предыдущем вопросе.
    Ответ написан
    Комментировать
  • Как применить топологическую сортировку?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно переписать под матрицу смежности вот этот участок кода.
    for(int i = 0;i < Edges[v].size();i ++){
              if(dfs(Edges[v].get(i)))return true;
          }

    Что-то типа этого.
    цикл (i : все вершины)
       если матрица_смежности[v, i]
             если dfs(i)
                 return true;

    Ещё мне не нравятся константы 0, 1 и 2. Объявить бы их как
    UNVISITED = 0;
    PARTLY_VISITED = 1;
    VISITED = 2;

    Или WHITE, GRAY и BLACK, если хотите — в учебниках по алгоритмам их красят в три цвета.
    Ответ написан
    Комментировать
  • Как правильно написать MutexLocker?

    @Mercury13
    Программист на «си с крестами» и не только
    pthread_mutex_locker locker(&mutex);

    Назови его как-нибудь, и всё будет окей.
    Ответ написан
    Комментировать
  • Зачем нужен ООП?

    @Mercury13
    Программист на «си с крестами» и не только
    Я хотел спросить: вы что, студент? Потом посмотрел: нет, вебист. Вебистам действительно ООП нужно крайне редко; если не связывался с хитрой поддержкой сложных протоколов или со сложными моделями данных — в памяти, не в БД — можно писать без ООП и быть успешным вебистом.

    Я и сам долгое время не понимал, на что нужны эти объекты. Главный вопрос: ДЛЯ ЧЕГО?

    Для того, чтобы передать взаимодействие кучи вещей. Где нет взаимодействия, там нет ООП, и можно заниматься, например, научными расчётами, на которые мало кто из нас способен, высший пилотаж, и вообще про ООП ничего не знать. Помню, как Вассерман — тот самый, некогда программист техпроцессов — долго-долго вспоминал, что такое ООП.

    Предлагаю начать с простого.

    1. Объектный синтаксис. Было…
    iDog : integer;
    iDog := SpawnMonster(world, mtDog, x, y);
    ChargeAtPlayer(iDog);


    Стало…
    dog : TMonster;
    dog := world.SpawnMonster(mtDog, x, y);
    dog.ChargeAtPlayer;


    Уже стало красивее. Да и номер собаки можно случайно передать, например, вместо номера оружия; с типом TMonster такой фокус не пройдёт.

    2. Инкапсуляция.
    Это мы уже думаем над тем, чтобы вызовы функций не могли привести объект в «ненадлежащее» состояние, а всё, что может объект подпортить,— засунуто в private.

    3. Абстракция и наследование. Это уже «сложный пилотаж». Не высший — это неотъемлемая часть навыков хорошего программиста, да и для 80% задач это не нужно, зато в остальных 20-и очень улучшает жизнь. Самый простой пример. В какой-нибудь 2D-игре есть некий TGameObject, у которого виртуальные функции Live и Render. Первая прокручивает такт «жизни» объекта, вторая рисует его на экране. TGameObject можно разбить на TPlayer, TProjectile, TEnemy и TBonus, и т.д.

    Ах да. Для ООП не нужен объектно-ориентированный язык и объектный синтаксис, нужно объектно-ориентированное мышление. Например, Doom был написан на Си, но в очень-очень объектном стиле.
    Ответ написан
    Комментировать
  • Какой аналог php функции is_string() в ЯП С++?

    @Mercury13
    Программист на «си с крестами» и не только
    C++ — язык со статической типизацией, и если x объявлено как string, то он всегда string. А если как int, то он никогда не string. Поэтому функция is_string в C++ просто не имеет смысла.

    Правда, существуют островки динамической типизации наподобие VARIANT из OLE — это уже смотрите по месту (msdn.microsoft.com/en-us/library/cc237865.aspx) и, скорее всего, это не ваш вопрос.

    Да, вы хотели проверять корректность ввода. Например, для проверки, будет ли строка числом, можно использовать www.cplusplus.com/reference/cstdlib/strtod (не забудьте потом проверить endptr!)
    Ответ написан
    Комментировать
  • Вопрос специалистам по GCC и темплейтам C++

    @Mercury13
    Программист на «си с крестами» и не только
    Всё, что я знаю: GCC — самый «въедливый» компилятор. После Intel и Embarcadero (про M$ не знаю) на «зашаблоненном» коде GCC найдёт ещё два десятка ошибок.
    Ответ написан
    Комментировать
  • Возможно ли создать "универсальный" драйвер для исполнения произвольного кода в Ring0?

    @Mercury13
    Программист на «си с крестами» и не только
    Это к Sony или StarForce. И те, и другие делали заSHITу и прокалывались на подобном.
    Ответ написан
  • Можно ли создавать в рантайме объект в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Разрешите вставить и свои 5e−2 Р

    Известно ли что-то о том, какой тип будет иметь наш auto? Если известно, то может, сработает просто

    dynamic_cast<Type>(object).field1.field2 = NULL;
    Ответ написан
    Комментировать
  • Разобраться со слабыми сторонами C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Что я могу сказать про проблемы C++?
    1. Слишком слабая типизация. Например, int x = 0.0;
    2. Система хедерных файлов крайне медленна, «предкомпилированные хедеры» и extern template — полумеры.
    3. Запутано подключение чужого откомпилированного кода (DLL, к примеру). Мало написать хедер, надо ещё откомпилировать lib — в общем, интересного мало.
    4. Библиотека STL крайне жирна. Хотя и libc тоже «хороша» — минимальная программа на Паскале занимала несколько килобайт, в зависимости от компилятора, на Си — приближается к сотне килобайт. Я не говорю про Linux/MSVC, где libc динамически подключаемая.
    5. Строковый литерал на C++ — это та же нуль-терминированная строка. Когда эту строку приходится оборачивать в какой-нибудь std::string, уже при выполнении вычисляется её длина. Зачем? Почему бы не вкомпилировать её в exe'шник?
    6. Нет ключевых слов override/reintroduce. При изменении сигнатуры виртуального метода приходится вспоминать, где он переопределялся.
    7. Нет виртуальных конструкторов. «Фабрика» — полумера.
    8. Коряво реализовано право доступа «читай кто угодно, пишу только я».
    9. Явное определение методов как inline или не-inline в сочетании с шаблонами приводит к странным эффектам. Когда расшаблонивание приводит к сложному коду, inline вреден (сжирает кэш процессора), когда к простенькой операции с указателем — наоборот, нужен. В общем, это давно уже должно стать парафией оптимизатора.
    10. В разного рода callback'ах замыкание приходится реализовывать собственными силами. Что-то типа: typedef void (*ProcDoSomething)(int aParam, void* aClosure). То же самое в Delphi: type ProcDoSomething = procedure(int aParam) of object;
    11. Если вдруг случайно два разных модуля реализуют одно и то же, но один препроцессором, а второй — синтаксисом C++, будет ОЧЕНЬ много геморроя с поиском ошибки.
    12. В обычном цикле for счётчик упоминается трижды. В общем, место очень ошибкоопасное. Для самых простых циклов у меня вообще есть макрос FOR_S (i, 0, n); суффикс S означает size_t.
    13. Когда из-за рефакторинга «внутренней кухни» объекта меняется способ хранения ссылки, меняется и код, который этой ссылкой пользуется. Например: object.buddy.field, object->buddy.field, object.buddy().field — в зависимости от того, buddy реализовано как Buddy& buddy, Buddy* buddy или Buddy buddy().

    Пока, засиделся. Мне бежать.
    Ответ написан
    4 комментария