Задать вопрос
Ответы пользователя по тегу C++
  • Ошибка с типами с++?

    @Mercury13
    Программист на «си с крестами» и не только
    1. C:\Users\XXX\Desktop — не обязательно стол будет там.
    2. Гуглите функцию std::string::c_str() — преобразование string в нуль-терминированную строку Си.
    Ответ написан
    Комментировать
  • Что означает данная запись структуры?

    @Mercury13
    Программист на «си с крестами» и не только
    Переменная этого типа.
    Ответ написан
    Комментировать
  • Какие бывают библиотеки для лицензирования, и бывают ли?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы посоветовал посмотреть открытые части VmProtect (там и на PHP версия есть, и на C++). Они связаны именно с лицензированием.
    А также поискать где-то структуру VmProtect’овского hardware ID.
    Закрытые части, связанные с защитой лицензий от взлома и собственно виртуальной машиной, которая и дала название защите VmProtect, вы вряд ли найдёте. Да и вообще защита от копирования не может быть опенсорсной.
    Ответ написан
    Комментировать
  • Как с помощью какой функции можно int PID преобразовать в Handle?

    @Mercury13
    Программист на «си с крестами» и не только
    CreateProcess, последний параметр: processInfo.hProcess.
    https://stackoverflow.com/questions/42531/how-do-i...
    Ответ написан
    3 комментария
  • Как вывести результат программы на cpp в ms excel?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть три варианта.
    1. Найти библиотеку работы с Excel. Самая маленькая и открытая — libxlsxwriter.
    2. Сохранять в более простых форматах. Самый простой из них — CSV. Не забудьте, что русский и английский Excel работают с разными CSV.
    3. Использовать OLE-автоматизацию Excel.
    У Спольского есть статья, почему форматы M$ Office такие сложные: https://rutlib5.com/book/25666/p/27
    Ответ написан
    Комментировать
  • Что означают надписи Ty, Alloc, Allocator в ошибке?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы попытались запустить функцию vector<A*>::erase с необычными параметрами. Какие — в ошибке не говорится, вот все перегрузки.
    https://ru.cppreference.com/w/cpp/container/vector...
    То есть функция принимает один или два итератора.

    Например, если вы хотите удалить значение, но неизвестно, где, нельзя его просто erase. А надо…
    // Спрессовать без перевыделения памяти, получить новый конец
    std::vector<A*>::iterator newEnd = std::remove(v.begin(), v.end(), whatToDelete);
    // Удалить освободившийся хвост скопом!
    v.erase(newEnd, v.end());


    Если вы хотите удалить по индексу…
    v.erase(v.begin() + indexToDelete);
    Ответ написан
  • Как правильно хэшировать файл большого размера?

    @Mercury13
    Программист на «си с крестами» и не только
    Я не понял, что значит «хэшировать». Если получить хэш-сумму — то все алгоритмы расчёта хэш-сумм позволяют скармливать файл небольшими блоками. И методика зависит библиотеки файлов и хэш-сумм, которой вы сейчас пользуетесь.
    Ответ написан
    Комментировать
  • Какая разница между передачей по указателю и по ссылке?

    @Mercury13
    Программист на «си с крестами» и не только
    О передаче объекта в функцию — обычно ссылка, НО!

    1. Если библиотека живёт на указателях (Qt) — указатель.
    void fillCombo(QComboBox* x) {}  // хорошо
    fillCombo(ui->comboHistory);
    
    void fillCombo(QComboBox& x) {}  // плохо
    fillCombo(*ui->comboHistory);


    2. Если возможен NULL — указатель. НО: существует паттерн «Null object», и он иногда бывает хорош.
    // Хуже, но возможно
    void import(AsyncRunner* asy) {
       if (asy) {
          asy->run([](){
            doImport(x);
          });
       } else {
          doImport(x);
       }
    }
    import(nullptr);
    
    // Лучше
    void import(AsyncRunner& asy) {
      asy.run([](){
        doImport(x);
      });
    }
    import(NoAsync::INST);


    3. Если передаём буфер данных — указатель.
    void write(size_t size, const char* data) {}

    4. Если объект невелик — значение.
    void save(std::string_view fileName) {}

    Объект может быть велик, но для него существуют специальные регистры — тогда…
    void transform(Matrix4 x) {}
    Есть одна машина с такими регистрами, не помню только, какая. Xbox?

    5. Идиома «by value + move», позволяющая избавиться от двух версий функции — Obj(string&) и Obj(string &&). Используется для объектов с простым перемещением и сложным копированием — обычно строк и структур STL.
    Obj::Obj(std::string aName) : name(std::move(aName)) {}
    Ответ написан
    Комментировать
  • Почему не любят c++ builder?

    @Mercury13
    Программист на «си с крестами» и не только
    Я работал, и профессионально тоже.
    1. Вторичен по отношению к Delphi, и те, кому нужна «амбаркадебра», осваивают Delphi. Носит на себе и Паскаль, и Си, и потому громадные EXE’шники.
    2. До недавнего времени — устаревший компилятор. Сейчас и под x86, и под x64 clang. Где-то до 2012 вообще x64 не было!
    3. Поставили не на тот кроссплатформенный фреймворк — не нравится мне FireMonkey.
    4. WinForms как-то проще в разработке.
    5. Долгое время — невнятная лицензионная политика «амбаркадебры».
    6. Долгое время — отсталость Delphi/VCL (например, нет Юникода).
    Ответ написан
    Комментировать
  • Как при изменение размеров окна удержать выведенный текст?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое, самое главное. WM_PAINT рисует содержимое окна целиком. Если нужны тысяча надписей — или рисуйте их тысячу штук, или отпечатайте на внеэкранный BITMAP, или ещё что-нибудь.

    Это экономит память: Win3 хреново, но работала на одном мегабайте, лично видел. Но имеет побочный эффект — если прога перестаёт отвечать, например, в 95 с её вытесняющей многозадачностью, WM_PAINT никак не вызовешь, и будет белое окошко. XP (вроде она) кэширует содержимое окна и выводит его, пока прога не отвечает.

    Второе. InvalidateRect в WM_PAINT не имеет смысла. Смысл этого вызова — попросить Windows перерисовать окно, когда получится.
    Ответ написан
    2 комментария
  • SwapBuffers/ glXSwapBuffers потребляет ровно 50% времени работы приложения(нагрузка неважна),в чём может быть причина?

    @Mercury13
    Программист на «си с крестами» и не только
    glSwapBuffers крутится в ожидании VSYNC’а. Потому и потребляет столько.
    Ответ написан
  • Как понять условие задачи?

    @Mercury13
    Программист на «си с крестами» и не только
    Подобный вывод используется, чтобы было понятно, что вы способны, если нужно, вычислить с точностью до обыкновенной дроби, но в длинную арифметику (а дроби бывают длинные) не лезть. Ибо реализации длинной арифметики различаются по эффективности от ЯП к ЯП, а в некоторых вообще нет штатной (внешние библиотеки в олимпиадном программировании запрещены).

    Числа P и Q высчитываем с точностью до остатка от деления на Z := 109+ 7.

    Авторы обещают, что Q mod Z ≠ 0. Z — простое. Тогда НОД(Q mod Z, Z) = 1. Так называемый расширенный алгоритм Евклида (гуглите!) позволяет подобрать такие числа, чтобы m(Q mod Z) + nZ = 1.

    Ваша задача — вывести ((P mod Z) · m) mod Z. Специально указал дважды mod Z: первое у вас будет при работе с числом P, второе — при генерации вывода.

    Почему так? Возьмём вместо здоровенного Z цифру поменьше, 17. Если у вас получился результат 100/400, при расчётах выйдет цифра 15/9, и 9·2+17·(−1) = 1, и ваша задача — вывести (15·2) mod 17 = 13.

    Если же у вас получилось, например, 35/140, при расчётах получается 1/4, 1·(−4)+17·1 = 1, и вы должны вывести (1·(−4)) mod 17 = 13. То есть: независимо от того, насколько сократимая дробь у вас получилась, вы получите один и тот же результат. Тут надо уточнить: там, где возможен отрицательный числитель, нужен не обычный % из Си++, а (a % Z; если получилось отрицательное — добавь Z).

    Ну а арифметических переполнений просто не допускайте, Z = 109 + 7 позволяет умножать в типе long long и не уходить в переполнение.

    UPD. То, что Z — простое, даёт несколько выгод. Часто результат бывает круглый, и простота требует честно считать остаток, а не угадывать. Ну и побочек меньше.
    Ответ написан
    3 комментария
  • Почему шарик застревает в стене?

    @Mercury13
    Программист на «си с крестами» и не только
    У вас тут переменная кадровая частота. Если за длинный кадр шарик ушёл далеко за стенку, короткий кадр его не сможет вытащить наружу и снова инвертирует скорость — шар застрял. (Я это с лёгкостью повторил функцией Windows 10 «Aero Shake»).

    В простейшем случае — определять, за какую стенку шар выскочил, и давать ему скорость такую, чтобы он возвращался в площадку. А не просто vx=−vx, независимо от того, куда эта скорость смотрит.

    Также стоит ограничивать длительность кадра, и если он, например, продлился больше 0,2 с — пусть игра в такой ситуации «запнётся». Случилось что-то нехорошее, и не хочется, чтобы всё слетело с катушек со своих позиций.

    Также надо давать float time = clock.restart().asMicroseconds(); Сейчас компы быстры и погрешность незначительна, но всё-таки.
    Ответ написан
    Комментировать
  • Почему "идентификатор не определён"?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Вытащи p, p1, p2 наружу из if. Читай «область видимости».

    2. Я бы сделал так…
    Work* p = NULL;
    if () {
      p = new Work();
    }
    delete p;

    Работает, потому что NULL можно спокойно уничтожать, и ничего не будет.

    На Си++11 можно также использовать умные указатели.
    std::unique_ptr<Work> p;
    if () {
      p = std::make_unique<Work>();  // простите, это Си++14, на 11 чуть не так.
    }
    Ответ написан
    Комментировать
  • Сhar *dictionary[][] = {}; Зачем тут const?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак. Да, строковый литерал — это const char[], преобразуемое в const char*.
    • Си++03 разрешал (но не одобрял).
    • Си++11 запрещает.
    • Одинаковые строковые литералы компилятор может преобразовать в один адрес, а также хранить в памяти, куда писать нельзя — потому const. И в Си без крестов тоже, только там попытка записи даст простой AV.
    • Const — это т.н. «cv-модификатор» (const-volatile), входит в систему типов Си++, устанавливается свободно, снимается операцией const_cast и означает, что объект нельзя изменять.
    Ответ написан
  • Есть ли в для C++14 map с поддержкой constexpr хэша?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, разумеется. ООП подразумевает смену состояния объекта, а в константных выражениях смена состояния запрещена. Может, и можно какую-то собственную горбушку придумать, но не знаю, как (даже конструктор — смена состояния).

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

    @Mercury13
    Программист на «си с крестами» и не только
    Egorithm, Отлично, теперь у вас есть файл библиотеки *.a, include-файлы *.h и разделяемая библиотека *.so.
    Задачи, в порядке приоритета.
    1. Заставить прогу компилироваться, для этого надо в проекте прописать доступ к include-файлам *.h.
    2. Заставить прогу линковаться, для этого надо в проекте прописать доступ к *.a (-lmuparser -L$$PWD).
    3. Заставить прогу запускаться, закинув куда надо *.so.
    Ответ написан
    1 комментарий
  • Как собрать библиотеку .lib [muParser]?

    @Mercury13
    Программист на «си с крестами» и не только
    Ну, раз уж решил пойти третьим путём (Как подкючить библиотеку [muParser] к Qt? ) — лови проект.

    Как вы видите, в большинстве случаев проект библиотеки строится тривиально: ищем, что надо включить в DEFINES, и затыкаем предупреждения.
    CONFIG -= qt
    
    TEMPLATE = lib
    CONFIG += staticlib
    
    CONFIG += c++11
    
    # The following define makes your compiler emit warnings if you use
    # any Qt feature that has been marked deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS MUPARSER_STATIC
    
    QMAKE_CXXFLAGS += -Wno-deprecated-copy -Wno-cast-function-type
    
    # You can also make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
        src/muParser.cpp \
        src/muParserBase.cpp \
        src/muParserBytecode.cpp \
        src/muParserCallback.cpp \
        src/muParserError.cpp \
        src/muParserInt.cpp \
        src/muParserTest.cpp \
        src/muParserTokenReader.cpp
    
    HEADERS +=
    
    INCLUDEPATH += include


    (ВНИМАНИЕ! Я использую новейший MinGW из MSYS, он на две версии новее, и, возможно, некоторые из предупреждений, которые я заглушил, не нужны.)

    В программе придётся указать
    DEFINES += MUPARSER_STATIC
    
    INCLUDEPATH += ../MuParser/include
    
    LIBS += -L$$PWD -lmuparser


    Если что, в MSYS тоже есть MuParser, хотя он у меня не установлен.
    pacboy sync muparser:i muparser:x
    Ответ написан
    Комментировать
  • Как подкючить библиотеку [muParser] к Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Тут есть несколько вариантов.
    1. Собрать *.a (любым подходящим методом), закинуть h-файлы в каталог include компилятора, *.a в каталог lib компилятора. В проекте добавить LIBS += -lmuparser.
    2. Закинуть исходный текст библиотеки куда-то в проект, добавить *.cpp (возможно, не все) в этот самый проект. Чтобы удобнее было подключать файлы, прописать INCLUDEPATH += muparser/include
    3. Промежуточный вариант — собрать *.a, закинуть его и *.h куда-то в проект. В проект добавить LIBS += -L$$PWD -lmuparser, INCLUDEPATH += muparser/include
    4. Собрать пакет для Qt. Как — не знаю.

    Когда каким методом пользуюсь.
    1. Только если библиотека есть в дистрибутиве MSYS.
    2. В подавляющем большинстве случаев.
    3. Иногда, особенно если библиотека большая. Ну и если авторы предлагают «официальную» DLL’ку — предварительно собрав, например, через Dependency Walker + DllTool подходящий *.a и заверсионировав его. (В больших проектах не обойтись без линкера LLD, но он, в отличие от LD, не подхватывает *.DLL, надо создавать файл библиотеки.)
    4. Если есть «официальный» пакет. Одна такая библиотека — QWT.
    Ответ написан
    1 комментарий
  • Восходящее преобразование массива производного класса к родительскому?

    @Mercury13
    Программист на «си с крестами» и не только
    Почему нельзя: если мы объявим ящик бананов ящиком фруктов и положим туда яблоко, он перестанет быть ящиком бананов.
    #include <iostream>
    
    class Vocal {  // интерфейс
    public:
        virtual void shout() = 0;
        virtual ~Vocal() = default;
    };
    
    class Dog : public Vocal {
    public:
        virtual void shout() override { std::cout << "Woof!" << std::endl; }
    };
    
    class Unrelated {};
    
    // ВАРИАНТ 1. Метод выкручивания рук.
    
    void shoutAll_v1(Vocal** x, int n)
    {
        for (int i = 0; i < n; ++i)
            x[i]->shout();
    }
    
    template <class T, int N>
    inline void shoutAll_v1(T* (&x)[N]) {
        // Тупая проверка концепции, ждём Си++20
        static_assert (std::is_base_of<Vocal, T>(), "Need array of Vocal");
        T** xx = x;
        shoutAll_v1(reinterpret_cast<Vocal**>(xx), N);
    }
    
    // ВАРИАНТ 2. Виртуальный полиморфизм.
    
    class Choir { // интерфейс
    public:
        virtual int size() const = 0;
        virtual Vocal& at(size_t i) const = 0;
        virtual ~Choir() = default;
    };
    
    void shoutAll_v2(const Choir& x)
    {
        int sz = x.size();
        for (int i = 0; i <sz; ++i)
            x.at(i).shout();
    }
    
    template <class T>
    class VocalArray : public Choir {
    public:
        template <int N>
        VocalArray(T* (&x)[N]) : fData(x), fSize(N) {}
        int size() const override { return fSize; }
        Vocal& at(size_t i) const override { return *fData[i]; }
    private:
        T** const fData;
        int fSize;
    };
    
    int main()
    {
        Dog* sons[3];
        for(auto& x : sons) {
            x = new Dog;
        }
        //Unrelated* unrel[3];
    
        std::cout << "V1" << std::endl;
        shoutAll_v1(sons);
        //shoutAll_v1(unrel);   не компилируется
    
        std::cout << "V2" << std::endl;
        shoutAll_v2(VocalArray<Dog>(sons));
        //shoutAll_v2(VocalArray<Unrelated>(unrel));  не компилируется
    
        return 0;
    }
    Ответ написан
    4 комментария