Задать вопрос
Ответы пользователя по тегу C++
  • Как написать 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…
    Рекурсивный удобнее для внутреннего формата хранения, когда надо в подходящем виде сериализовать всё, что в программе есть, да ещё и наладить поддержку старых версий этой сериализации.
    Ответ написан
    Комментировать
  • Какими приёмами вы пользуетесь чтобы различать указатели, которые нужно освобождать, от указателей, которыми нужно только пользоваться?

    @Mercury13
    Программист на «си с крестами» и не только
    Но есть ещё один указатель, который реализует именно что единую ответственность — std::unique_ptr. Также я использую одну самоделку — но, возможно, «не умею готовить» unique_ptr.
    Ответ написан
    1 комментарий
  • Какие обьекты удалять в деструкторе?

    @Mercury13
    Программист на «си с крестами» и не только
    После того, как отработает тело деструктора, для всех полей объекта автоматически вызываются деструкторы, в обратном порядке.
    У int и double деструкторы нулевые — но другие-то и не нужны.

    В каких случаях надо писать деструктор самим…
    1. Мы владеем каким-то ресурсом, но штатный деструктор его не уничтожает.
    • Простой (не умный) указатель и выделенная память — это хорошо описал sitev_ru .
    • Объект-блокировщик, например, мьютекса (мьютекс — примитив межпоточной синхронизации, не дающий зайти в определённые участки кода одновременно двум потокам).
    class Mutex {
    public:
      void enter();
      void leave();
    }
    
    class Lock {
    public:
      Lock(Mutex& aMutex) : mutex(aMutex) { mutex.enter(); }
      ~Lock() { mutex.leave(); }
    private:
      Mutex& mutex;
    }
    
    …
    Mutex mutex;
    { Lock lock(mutex);
      // всё, что здесь, выполняется внутри мьютекса.
      // Даже если выпадет авария, из мьютекса корректно выйдем.
    }

    2. Сложный порядок уничтожения. Односвязный список из std::unique_ptr будет работать и так, со штатным деструктором, но это чревато переполнением стека.
    3. Сложная структура владения, и при уничтожении надо автоматически отобрать объект у владельцев. По-чёрному используется в оконных фреймворках на манер VCL и Qt. Удаляем компонент — он автоматически отбирается у владельца.

    По опыту: если структуры данных выносить в отдельный объект (ну и использовать STL, где можно), 80% объектов Си++ будут с автоматическим деструктором.

    ЗЫ. По результатам прикидочных подсчётов в живом проекте, ≈150 файлов (реально файлов 219, но не все наши собственные; библиотечные деструкторы не учитывал).
    • Классов с настоящим деструктором — около 30. Большей частью системные (W32Cs — быстрый мьютекс Win32) или структуры памяти (Array1d, например). Из них в собственно проекте (не в личной библиотеке программиста) — три (!): один связан с автовладением чужой библиотекой XLSX, два — с фоновыми потоками.
    • Интерфейсов с пустым виртуальным деструктором — порядка 40.
    • И ещё деструкторы, автоматически добавленные Qt — по числу форм, ровно 20.
    • И единицы пустых деструкторов, добавленных по желанию левой пятки линкера.
    Ответ написан
    Комментировать
  • Как подсчитать комбинацию шагов коня на матрице 4 на 3?

    @Mercury13
    Программист на «си с крестами» и не только
    Твоё дело — перебор с кэшированием.
    Для каждой кнопки вручную закидываем в массив конских «соседей» — ни одного для 5-ки, три для 4 и 6, два для остальных.
    Затем заведи массив 10×7 (стартовая кнопка×длина) и устрой рекурсию с одним небольшим добавлением: если оно закэшировано, брать из кэша. Правила — f(b, 1) = 1, для остальных — sum{c=сосед(b)} f(c, i−1).
    Можно и динамическим программированием, без рекурсии — всё равно расход вычислительной мощи незначительный. Сначала f(b, 2), затем f(b, 3), и т.д. до 7.
    Ответ написан
  • Освобождается ли память по завершению выполнения функции, если массив инициализировать внутри функции?

    @Mercury13
    Программист на «си с крестами» и не только
    char * a = "hello!";
    Для указателя a — разумеется, на стеке.
    Строка, на которую он смотрит, "hello",— строковый литерал. Для него память изначально, при пуске программы выделена в сегменте данных. Освобождать не надо. На многих платформах — хоть на это рассчитывать не надо — этот сегмент защищается от записи и при попытке туда записать AV.
    Ответ написан
    8 комментариев
  • Разработка под Windows - MSVC или TDM GCC (MinGW)?

    @Mercury13
    Программист на «си с крестами» и не только
    3) Использование инициализации списком для структур (POD) с уже прединициализированными полями:

    Это C++11. Хорошее дело. MinGW поддерживал, пока стандарт ещё вырабатывался. MSVC начал было, да бросил и довёл до конца аж в 2015!!

    1) Разное содержимое одних и тех же хедеров

    Не выбивается из стандарта.

    2) MSVC спокойно компилирует нечто вроде

    MSVC ошибается, таким образом неконстантную ссылку передавать запрещено.

    но при этом не компилирует код, если не-void функция не возвращает значение

    Хорошая диагностика, но это лишь warning, а не error. Компилятору трудно знать, возможен ли тот или иной путь исполнения кода.
    Ответ написан
    Комментировать
  • С++: Вызов различных конструкторов в зависимости от пользовательского ввода?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Свой код — сделать функцию init
    Foo foo;
    if (someFlag)
      foo.init("SomeString");
      else foo.init(42);

    2. Чужой код — сделать обёртку, которая в init будет использовать placement new, а в деструкторе — явно вызывать деструктор объекта.
    class FooWrap {
    public:
      FooWrap() : hasFoo(false) {}
      void init(int x) { new (fooPlace) Foo(x); hasFoo = true; }
      Foo& operator * () { return *reinterpret_cast<Foo*>(fooPlace); }
      Foo* operator -> () { return reinterpret_cast<Foo*>(fooPlace); }
      ~FooWrap() { if (hasFoo) (*this)->~Foo(); }
      // Да, и конструктор копирования и op= не забыть — оставлю как упражнение.
    private:
      char fooPlace[sizeof(Foo)];
      bool hasFoo;
    }
    
    FooWrap foo;
    if (someFlag)
      foo.init("SomeString");
      else foo.init(42);
    foo->doFoo();

    Для большей надёжности стоит указать, что FooWrap выравнивать как Foo — это делается через C++11 или расширениями компилятора.
    Ответ написан
    3 комментария
  • Как добавить динамическую библиотеку в проект напрямую?

    @Mercury13
    Программист на «си с крестами» и не только
    Задача lib — указать если не код функций, то хотя бы каким образом их прилинковывать из DLL. В частности, как «искозявлено» имя функции при переводе с Си на Си++. Этот самый lib — издержка разделения функций между компилятором и линкером.
    Не знаю, как MSVS/cl, но MinGW/ld с определённого момента начал прилинковывать DLL просто по наличию этого DLL, без построения *.a (а Embarcadero/ilink32, насколько мне известно, умел это изначально). С одной стороны, это серьёзно упрощает жизнь. С другой — для некоторых хитрых способов преобразования имён (или даже без имён, как в небезызвестном storm.dll) он не выцепит, что с чем слинковывать, *.a всё равно потребуется.
    stackoverflow.com/questions/31708832/how-to-refere...
    www.codeproject.com/Questions/613668/Is-it-possibl...
    Простейший, действующий на любом компиляторе способ — это сделать DLL-заглушку со всеми нужными нам функциями в нужных нам соглашениях вызова и с нужным образом закозявленными именами. Код может быть любым, хоть пустым. Компилируем, подставляем этот lib и правильный DLL.
    Второй способ — получить список имён функций, собрать их в *.def с правильными соответствиями «имя в коде — имя в DLL» и сделать из этого *.lib. Какими программами это делается в MSVS — описано по одной из ссылок.
    Ответ написан
    2 комментария
  • Динамический массив строк, используя string, в чем проблема?

    @Mercury13
    Программист на «си с крестами» и не только
    i++;
        a[2] = "monday";

    Выход за пределы массива. Массив длины 2 имеет два элемента: [0] и [1].
    Ответ написан
    Комментировать
  • Когда имеет значение порядок подключения заголовочных файлов?

    @Mercury13
    Программист на «си с крестами» и не только
    Заголовочные файлы надо писать так, чтобы порядок их подключения был неважен.

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

    Совать #include в пространство имён без хорошего обоснования не стоит.

    По вашему обтекаемому описанию не видно, как устроены ваши заголовки, именованное пространство имён или нет, закрыты ли все скобки в хедерах, и т.д. Но причина ошибки очевидна: из-за пространств имён компилятор не отождествил классы в первом и втором заголовке; предварительное объявление «class A;» осталось неразрешённым. Поэкспериментировав, я выяснил вот что.
    // Не компилируется!
    class A;
    
    namespace XXX {
        std::shared_ptr<A> a;
        class A { public: int x; };
        void xxx();
    }
    
    void XXX::xxx() {
        a->x;
    }


    // Компилируется!
    class A;
    
    namespace XXX {
        class A { public: int x; };
        std::shared_ptr<A> a;
        void xxx();
    }
    
    void XXX::xxx() {
        a->x;
    }

    // Тоже компилируется!
    namespace XXX {
        class A;
    }
    
    namespace XXX {
        std::shared_ptr<A> a;
        class A { public: int x; };
        void xxx();
    }
    
    void XXX::xxx() {
        a->x;
    }

    В первом случае shared_ptr<::A>, который, естественно, не определён (есть XXX::A).
    Во втором — определение наперёд ::A вообще ни на что не сдалось; используется shared_ptr<XXX::A>.
    В третьем примере только один тип, XXX::A.

    Если первым идёт не использование, а make_shared — выходит другая ошибка, не удаётся получить sizeof недоопределённого типа A.
    Ответ написан
    2 комментария