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

    @Mercury13
    Программист на «си с крестами» и не только
    Это называется фрагментация памяти. Некоторые «мусорщики» (как в Java или C#) способны сдвинуть объекты и получить большой непрерывный отрезок.
    Менеджер памяти C++ дефрагментировать память не способен и выдаст нехватку памяти.
    В любом случае, массив — что в Java, что в C++ — будет занимать непрерывный отрезок памяти.

    Чтобы совмещать мусорные языки с системными интерфейсами, есть способы пометить структуру как неперемещаемую. Но это уже на стыке виртуальной машины Java/C# и системного кода, который пишется на Си(++).
    Ответ написан
    9 комментариев
  • Почему не сохраняет и не выводит последнее введенное число?

    @Mercury13
    Программист на «си с крестами» и не только
    Код while (cin >> val) подразумевает, что мы ждём конца консоли.
    Если консоль перенаправлена из файла — ну, с этим всё понятно.
    А если нужно сделать конец в настоящей консоли, нажмите Ctrl+Z.

    Код высчитывает количество введённых подряд одинаковых чисел; если мы вводим другое или заканчиваем поток — он выводит, сколько их было.
    Ответ написан
    Комментировать
  • Qmake not using precompiled headers?

    @Mercury13
    Программист на «си с крестами» и не только
    По документации Qt, нельзя.

    Зато можно исключить Си++ из предкомпиляции простым методом.

    // Add C includes here
    
    #if defined __cplusplus
    // Add C++ includes here
    #include <stdlib>
    #include <iostream>
    #include <vector>
    #include <QApplication> // Qt includes
    #include <QPushButton>
    #include <QLabel>
    #include "thirdparty/include/libmain.h"
    #include "my_stable_class.h"
    ...
    #endif


    doc.qt.io/qt-5/qmake-precompiledheaders.html

    Самому так пригодилось (правда, на MinGW, а не на MSVC).
    Ответ написан
    1 комментарий
  • Как реализовать наследование статического поля/метода, если это возможно?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое. Объясни, для себя и для меня, что собой представляет объект Command?

    Моё видение — разделить объекты Command (введённая пользователем и разобранная строка) и Program (программа, реализующая команду). Также я нарисовал — хочешь, используй, хочешь, нет — объект Console (консоль ввода-вывода) и System (окружение программы вроде текущего каталога, переменных окружения, файловой системы).

    Я тут работаю со значениями и указателями, в терминах C++03, но, возможно, вас заинтересуют умные указатели C++11.

    std::string commandLine = console.getSomeCommandLine();
    Command command;
    std::string error;
    if (!command.parse(commandLine, error)) {
      console.err().writeln(error);
      return;
    }
    Program* program = system.findProgram(command.programName);
    if (!program) {
      console.err().writeln("Bad command or file name");
      return;
    }
    Console redirectedConsole = console.redirectStreams(command);
    program->exec(redirectedConsole, system, command.getArguments());


    Второе. Возвращай ссылки, это быстрее.
    const std::vector<std::string>& getArguments() const;
    const std::vector<std::string>& getOptions() const;
    Ответ написан
  • Почему не работает libcurl?

    @Mercury13
    Программист на «си с крестами» и не только
    Как ни странно, нужна версия libcurl с поддержкой HTTPS.
    Большинству таких версий в нагрузку нужны два файла OpenSSL — libeay32.dll, ssleay32.dll.
    Ответ написан
    Комментировать
  • Ошибка C++ Builder XE Unable to open file 'ODBCPROVIDER150.OBJ'. Кто-нибудь поможет?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Этого файла не будет, он скрыт в файле с расширением lib. Найдём его. Если нет — значит, библиотека не была скомпилирована под Builder.
    2. Tools → Options → C++ Options → Paths and Directories → Library Path.
    Ответ написан
    Комментировать
  • Qt. Как использовать сигналы-слоты?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, мы заводим где-то новый слот и подаём сигнал в него.
    Есть два способа завести новый слот: либо унаследоваться от QObject или его наследника (удобно унаследовать главную форму), либо воспользоваться лямбда-функцией C++11. Поскольку все наши формы на стеке, проще всего написать лямбду.

    connect(&Button, &QPushButton::clicked, 
                &Base, [&]() {
            // тут код
        });


    В реальных проектах каждая форма является наследником от QWidget (или чего-то подобного) и хранит свои компоненты. А слоты — это функции в форме.
    Ответ написан
    7 комментариев
  • C++ Builder и ProgressBar. Как сделать постоянное отображение квадратика бегающего слева направо?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно дать возможность оконным сообщениям ходить и обрабатываться.

    Простой способ. Поминутное Application->ProcessMessages().
    Сложный способ. Вынести долгую операцию в поток.

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

    @Mercury13
    Программист на «си с крестами» и не только
    Что вы имеете в виду? Инициализировать и закрыть библиотеку по мере появления-исчезновения объектов? Вот мой код (работает с cURL, но понятно).

    В чём его смысл? Как только объект cURL требуется первый раз, инициализируем глобальный объект. Теперь, скорее всего, cURL будет разрушен с его деструктором. Но если в каком-то потоке объект cURL будет слишком долго жить — ничего, подождём.

    (Внимание, тут гонка, если одновременно потребуются два объекта cURL. Нам такое не нужно, но если вдруг — защитите по принципу Singleton’а.)

    namespace curl {
    
        std::atomic<size_t> nLib(0);
    
        class _Lib
        {
        public:
            bool isIn = false;
            ~_Lib();
        };
    
        _Lib lib;
    
        void addLib()
        {
            int q = ++nLib;
            if (q == 1) {
                lib.isIn = true;
                q = ++nLib;
                curl_global_init(CURL_GLOBAL_ALL);
            }
            //std::cout << "Added lib, now " << q << std::endl;
        }
    
        void releaseLib()
        {
            int q = --nLib;
            if (q == 0) {
                //std::cout << "Cleaned up lib" << std::endl;
                curl_global_cleanup();
            } else {
                //std::cout << "Released lib, now " << q << std::endl;
            }
        }
    
        _Lib::~_Lib()
        {
            if (isIn)
                releaseLib();
        }
    
    }
    
    curl::Curl::Curl()
    {
        addLib();
        fData.handle = curl_easy_init();
    }
    
    curl::Curl::~Curl()
    {
        if (fData.handle)
            curl_easy_cleanup(fData.handle);
        releaseLib();
    }
    Ответ написан
    Комментировать
  • Как перевести число в строку с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Ошибка вот где.
    else {
                cout<<"False";
                return 0;
            }
        }

    Проверяет только первую цифру, и если она не 3 — сразу же говорит false.
    Ответ написан
  • Часто ли .net программисты сталкиваются в работе с с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Существует версия C++ для .NET — называется C++/CLI. Но в целом нет нужды в управляемой мусорной среде писать на C++, языке, рассчитанном на старый добрый машинный код и который таскает в архитектуре кучу «хвостов» времён ассемблеров.
    Так что мой ответ — в 99% случаев нет.
    Ответ написан
    Комментировать
  • Можно ли сделать массив меток goto?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы не представляете себе, так обычно и работает switch.
    prog21.dadgum.com/166.html
    Ответ написан
    5 комментариев
  • Как на C++ узнать количество передаваемых аргументов?

    @Mercury13
    Программист на «си с крестами» и не только
    Какие есть способы физически, на уровне машинного кода, передать переменное число параметров в подпрограмму?

    1. Автобоксинг в массив. Если к тому же тип элементов может быть любым — тогда будет массив «лёгких» или обычных variant’ов, или массив объектов на «куче». В Delphi для этого используется лёгкий variant (см. SysUtils.Format), в Java и других «мусорных» языках — объекты на куче. В Си++ нет.

    2. Автоматически развернуть такой вызов в кучу вызовов поменьше. См. вариативные шаблоны C++11 = variadic templates. В Си++ есть, штука тяжёлая, я с ней и сам знаком поверхностно и ничего толком рассказать не могу. Но вот кое-что набросал.
    #include <iostream>
    
    constexpr int countArgs() { return 0; }
    
    template <class Arg, class ... Args>
    constexpr int countArgs(const Arg& x, const Args& ... args)
    {
        return countArgs(args...) + 1;
    }
    
    int main()
    {
        std::cout << countArgs() << std::endl;
        std::cout << countArgs(1, 2, 3) << std::endl;
        return 0;
    }

    Может быть, и первый путь удастся завернуть в массив через вариативные шаблоны, но я не в курсе. А вот обрабатывать аргументы по одному — за милую душу!

    3. Использовать особые соглашения вызова и раскручивать стек, пока не попадётся какой-то маркер «больше параметров нет» (см. работу с формами cURL), или окольным путём узнать количество параметров (см. printf). Есть даже в Си (который не что иное, как «ассемблер высокого уровня»), штука очень системная и чреватая ошибками.

    4. Возможна ещё и такая фишка: физически оно устроено как printf, но обёрнуто в «лёгкий» вариативный шаблон, который защищает всё это добро от ошибок программиста.
    #include <iostream>
    #include <cstdarg>
    
    constexpr int countArgs() { return 0; }
    
    template <class ... Args>
    constexpr int countArgs(int x, Args ... args)
    {
        return countArgs(args...) + 1;
    }
    
    void outArgsInner(int count, ...)
    {
        va_list ap;
        va_start(ap, count);
        if (count > 0) {
            std::cout << va_arg(ap, int);
            for (int i = 2; i <= count; ++i) {
                std::cout << ' ' << va_arg(ap, int);
            }
        }
        va_end(ap);
        std::cout << std::endl;
    }
    
    
    template <class ... Args>
    inline void outArgs(Args ... args)
    {
        outArgsInner(countArgs(args...), args...);
    }
    
    int main()
    {
        outArgs();      // пустой тоже работает
        outArgs(1, 2, 3);
        // outArgs("a", 2, 3);   тут ошибка! — и верно, мы принимаем только int’ы
        return 0;
    }
    Ответ написан
    Комментировать
  • Как лучше задать табличную функцию с редкой областью определения?

    @Mercury13
    Программист на «си с крестами» и не только
    Если аргументы до 100, функция заранее известна и неизменна — чхайте на всё и делайте простым массивом. Именно так, таблицей переходов, внутри устроен switch. Всё, что я пишу ниже — для общего развития.

    Это называется «разреженный массив» (sparse array)

    1. Хэш-таблица (std::unordered_map).
    Преимущество: есть «в коробке», очень быстра.
    Недостаток: ест много памяти.

    2. Я также использую вот такой механизм.
    template <class T>
    class ChunkMap
    {
    public:
        // Data access
        //------------------------------------------------------------------------//
        /// @return  data at index t, or empty value
        T get(size_t t) const;
    
        //------------------------------------------------------------------------//
        /// Sets data at index t (empty value to erase)
        void put(size_t t, T x);
    
        //------------------------------------------------------------------------//
        /// Erases range [0..maxPlus)
        void eraseTo(size_t aMaxPlus);
    
        // Info
        size_t nChunks() const { return fChunks.size(); }
        bool isEmpty() const { return fChunks.empty(); }
    
        //------------------------------------------------------------------------//
        /// @return  the number that is beyond all chunks
        size_t ceil() const;
    
        //------------------------------------------------------------------------//
        /// @return  actual number of records in the map
        size_t size() const;
    
        //------------------------------------------------------------------------//
        /// @return  lowest value in the map; (0, empty) if empty
        std::pair<size_t, T> lowerValue() const;
    
        //------------------------------------------------------------------------//
        /// @return  highest value in the map; (0, empty) if empty
        std::pair<size_t, T> upperValue() const;
    
        //------------------------------------------------------------------------//
        /// @return  (t1, v), t1 <= t;  (0, empty) if none
        std::pair<size_t, T> lowerOrEq(size_t t) const;
    
        template <class Body> void loop(const Body& r) const;
        template <class Body> void loopFrom(size_t aMin, const Body& r) const;
    
        //------------------------------------------------------------------------//
        ///  Loops all data. Body is bool-convertible.
        ///  Return true → go on.
        ///  Return false → stop and return false.
        template <class Body> bool loopBool(const Body& r) const;
    
        void clear() { fChunks.clear(); }
    
        constexpr static T emptyValue() { return std::numeric_limits<T>::max(); }
        static bool isEmptyValue(const T& x) { return (x == emptyValue()); }
    
        constexpr static unsigned chunkSize() { return Chunk::SIZE; }
    
    private:
        struct Chunk
        {
            enum { SIZE = 8 };
            Fix1d<T, SIZE> data;   // мой шаблон, массив фиксированного размера с проверкой на выход за границы
    
            Chunk();
            bool isEmpty() const;
            std::pair<size_t, T> lowerValue(size_t aKey) const;
            std::pair<size_t, T> upperValue(size_t aKey) const;
        };
        typedef std::map<size_t, Chunk> Chunks;
        Chunks fChunks;
    };

    Можно делать и на unordered_map при желании, но мне нужна lowerOrEq().

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

    3. Вот ещё есть реализация на Java.
    https://android.googlesource.com/platform/framewor...
    Преимущество: серьёзная экономия памяти.
    Недостатки: когда массив велик (тысячи заполненных элементов), снижается скорость доступа. Большие расходы на чистку мусора.
    Ответ написан
    Комментировать
  • Как обрабатывать события в Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы, разумеется, орудуете встроенным в Qt Creator редактором форм…
    1. Визуально: ПКМ, Go to slot…
    Программно: функцией connect, это описал AtomKrieg.
    2. Все компоненты находятся в доп. объекте ui. Когда вы делаете форму программно, им не обязательно там быть, но редактор форм делает именно так.
    if (ui->textEdit->text() == "Hi") label->setText("Hi!");
    Ответ написан
  • Как задать програмнно отобразить поверх других форм форму вызванную через Show()?

    @Mercury13
    Программист на «си с крестами» и не только
    Комментировать
  • Передача данных по ftp. Как сделать?

    @Mercury13
    Программист на «си с крестами» и не только
    Наиболее известная штука — cURL. Помимо FTP, поддерживает FTP+TLS и SFTP.
    Вот пример для FTP-закачки.
    https://curl.haxx.se/libcurl/c/ftpupload.html

    На C++ лучше использовать «плюсовые» обёртки для cURL, но код в целом такой же.
    Ответ написан
    Комментировать
  • Как рисовать на QPixmap?

    @Mercury13
    Программист на «си с крестами» и не только
    Ваши ошибки.
    1. QPixmap — сам по себе указатель совместного владения; если надо его ненадолго создать — делайте на стеке, никаких new!
    1.1. Аналогично и QPainter, только он указатель единоличного владения. Кстати, это однажды сыграло с одной моей программой злую шутку, когда она выжрала всю память.
    2. Зачем нужна генерация Pixmap’а в процедуре перерисовки формы? Если ваш потомок сам корректно рисует картинку — генерируйте её по событию «что-то изменилось».

    Далее, если картинок может быть конечное, но достаточно большое число (например, тысячи), можно наладить кэш, где хранятся подготовленными, например, последние двадцать. Если картинок немного (до сотни), лучше при загрузке программы подготовить их все.
    Ответ написан
    Комментировать
  • Почему возникает ошибка LNK2001 Неразрешенный внешний символ символ?

    @Mercury13
    Программист на «си с крестами» и не только
    Как говорят, «или крест снимите, или трусы наденьте». И учите понятие «единица компиляции».
    По какой схеме устроен ваш проект? «Одна единица компиляции» или «много единиц компиляции»?

    Си недалеко ушёл от ассемблеров. А в ассемблерах программа компилировалась по частям и собиралась воедино линкером (компоновщиком, редактором связей) — в те времена кода было много, а данных мало. Многие из ошибок невозможно было определить, не запустив линкер. Си++ пользуется многими из архитектурных особенностей ассемблеров и Си — по крайней мере ни одно из модульных решений не стало рекомендацией (кроме костыля extern template class).

    Но как говорить «переменная/функция есть, такого-то типа и в другой единице компиляции»? Для этого есть прототипы функций и extern-определения переменных. Их обычно вносят в заголовочные файлы с таким требованием: ничего, что находится в заголовочном файле, не должно производить кода. А код производят…
    • Глобальные переменные (без typedef, extern).
    • Нешаблонные функции (кроме inline).
    • Полностью специализированные шаблонные функции (кроме inline).
    • Команда «специализировать шаблон» (template class).

    При этом…
    • Функции в теле struct/class автоматически inline и кода не производят.
    • Для неявной специализации шаблонов существуют обходы — код генерируется дважды, но ошибки не выдаёт.
    • «Свой» хедер обычно включают первым, чтобы убедиться, что в нём нет недостающих зависимостей.

    В системе «одна единица компиляции» всё просто: есть ровно один файл, подлежащий компиляции. Тогда в хедерных файлах вполне могут быть конструкции, производящие код.

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

    // В схеме «одна единица компиляции»: ничего не делать.
    // В схеме «много единиц компиляции»: лишняя зависимость; унести в unit1.cpp
    #include <cstdlib>
    
    // В схеме «одна единица компиляции»: убрать extern.
    // В схеме «много единиц компиляции»: завести unit1.cpp, там сделать MyType x;
    extern MyType X;
    
    // В схеме «одна единица компиляции»: ничего не делать.
    // В схеме «много единиц компиляции»: перенести функцию в unit1.cpp, оставив в .h только прототип.
    void XReset() {}
    Ответ написан
    Комментировать
  • Как написать SMTP-клиент, чтобы не попасть в список спамеров?

    @Mercury13
    Программист на «си с крестами» и не только
    Да уж, злой там спамодетектор…
    Написать сообщение реальным почтовиком и повторить как можно больше полей из этого самого почтовика.
    Пожалуй, главное — User-Agent. Процентов 80 ботофильтров ссылаются именно на него.
    Ответ написан
    Комментировать