Задать вопрос
Ответы пользователя по тегу C++
  • Часто ли .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 ботофильтров ссылаются именно на него.
    Ответ написан
    Комментировать
  • Как сделать двухстрочную шапку в таблице в С++ Builder?

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

    @Mercury13
    Программист на «си с крестами» и не только
    UPD. Теперь понял, о чём вы. В таком виде нельзя.
    Ответ написан
  • Почему a=1, i=1, j=2?

    @Mercury13
    Программист на «си с крестами» и не только
    Всё логично. Операция || даёт единицу, если хотя бы один параметр не 0, и ноль — если оба нули.
    К тому же операция || «экономная». Если первый аргумент не ноль — результат автоматически 1.

    i = 1
    1 || ? = 1,
    j++ не вычисляется вообще.
    Ответ написан
    Комментировать
  • Как заполнить динамически созданный массив?

    @Mercury13
    Программист на «си с крестами» и не только
    Кода нет даже игрушечного, и гарантированно не скажешь. Я вижу три возможных причины.
    1. Либо не прописан конструктор копирования или операции присваивания (а с деструктором всё в порядке). Указатели продолжают обращаться к освобождённой памяти, и по какому-то счастливому совпадению первый элемент совпадает.
    2. Либо конфликт имён: fn — параметр конструктора и fn — внутреннее поле.
    3. У вас тут закомментированное srand(time(NULL));. Я не знаю, что в функции random_at_most, но если там srand — перенеси его в другое место. Процессор работает в миллион раз быстрее, чем таймер. «Хочешь, чтобы было случайнее», а будут повторы.
    Ответ написан
    Комментировать
  • GetModuleFileNameA, в чем проблема?

    @Mercury13
    Программист на «си с крестами» и не только
    sz = strlen(szPath);
    Ну чему, блин, равняется sz?


    Return value

    If the function succeeds, the return value is the length of the string that is copied to the buffer, in characters, not including the terminating null character. If the buffer is too small to hold the module name, the string is truncated to nSize characters including the terminating null character, the function returns nSize, and the function sets the last error to ERROR_INSUFFICIENT_BUFFER.

    Вот оттуда надо брать длину. А не из strlen неинициализированной памяти.

    И идеалом было бы заложиться на пути длиннее MAX_PATH.
    Ответ написан
    Комментировать
  • Как работать со строковыми матрицами?

    @Mercury13
    Программист на «си с крестами» и не только
    Простейший способ — отсортировать каждую строку обеих матриц. Строки, изначально являвшиеся анаграммами, будут совпадать, и теперь уже можно выяснять, что с чем совпадает. Сложность O(w·(hA+hB)·max{hA+hB, log w})

    Более сложный (лучше асимптотическая оценка). После того, как отсортировали каждую строку, строки матрицы B дополнительно переупорядочиваем в лексикографическом порядке (ААА < ААБ <…< ААЯ < АБА). Для поиска совпадений пользуемся двоичным поиском. Сложность O(w·(hA+hB)·log max{w, hA, hB}).

    Можно также каждой строчке матрицы B посчитать хэши и запомнить в какой-то структуре данных: хэш не совпал ни с чем — полное сравнение не проводится. Не улучшает оценки в худшем случае, но улучшает в среднем.

    Офтоп. Было дело, я оптимизировал WAD’ы Doom’а по размеру (формат позволял нескольким блокам ссылаться на один и тот же участок файла, а во многих модах — и даже в самом Doom’е — были повторы). Обошёлся хэшированием, и хэшем был размер + несколько байт из середины блока.
    Ответ написан
    Комментировать
  • Как правильно унаследовать виджет QT?

    @Mercury13
    Программист на «си с крестами» и не только
    Наследоваться-то надо от QListWidget…
    Ответ написан
    2 комментария
  • C++ удаления дубликатов, почему не работает?

    @Mercury13
    Программист на «си с крестами» и не только
    void Wid::test() {
        vector<string> stp;
        stp.push_back(text->toPlainText().toStdString());
        // В stp одна штука
        sort(stp.begin(),stp.end());
        // Ну что ей будет, этой штуке?
        stp.erase(unique(stp.begin(),stp.end()),stp.end());
        // unique даст end; поведение vector при этом не определено.
        ofstream filesave(pp);
        copy(stp.begin(),stp.end(), ostream_iterator<string>(filesave,"\n"));
    }
    Ответ написан
    3 комментария
  • C++QT5: UTF-8, QString, QByteArray, *char и русские символы. Как изменить элемент в массиве *char?

    @Mercury13
    Программист на «си с крестами» и не только
    В кодировке UTF-8 один символ — это от одного до четырёх байт. Смиритесь, и если хотите менять русскую букву (2 байта) на английскую (1 байт), лучше работать в кодировке UTF-16.
    word1 = word;
    word1[0] = 'X';

    или
    word1 = QString::fromUtf8(ar.data());
    word1[0] = 'X';

    А если нет возможности — то разбирать UTF-8, разумеется.

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

    @Mercury13
    Программист на «си с крестами» и не только
    Портяночный способ хорош, когда на выходе — файл простой структуры. Например, стандартные файлы межпрограммного обмена наподобие HTML, PNG…
    Рекурсивный удобнее для внутреннего формата хранения, когда надо в подходящем виде сериализовать всё, что в программе есть, да ещё и наладить поддержку старых версий этой сериализации.
    Ответ написан
    Комментировать