Задать вопрос
Ответы пользователя по тегу C++
  • Как конвертировать list в string[]?

    @Mercury13
    Программист на «си с крестами» и не только
    Итератор — это объект с семантикой указателя, который может указывать на N+1 точку в объекте.
    5f40aef227644b9ca57224ffeb571a97.png
    Раз он с семантикой указателя, у него есть операции «унарная звезда» и −> (разыменование и разыменование+взятие поля). Также у итератора есть операция ++ (сдвинуться на следующую позицию). Если это т.н. «однонаправленный итератор» — всё, больше ничего.

    Также бывают т.н. двунаправленные итераторы (есть операция −−), и итераторы произвольного доступа (их можно свободно складывать с числами — ну совсем как указатели). В частности, у std::list итераторы двунаправленные.

    У итераторов неопределённое поведение…
    • при попытке выйти за начало или конец;
    • при попытке разыменовать, если он смотрит на последнюю позицию (отмеченную как «конец»).

    Конкретно о задаче.
    1. std::vector предпочтительнее std::list.
    2. Не нужно возвращать string*, хватает какого-нибудь контейнера (std::vector<std::string> или std::list<std::string>).
    3. Если функциональности и скорости istringstream хватает, флаг в руки! Я бы написал по хардкору, с нуля. Вот мой код, выдранный из моего проекта, наверно, будет несложно переделать его в учебный.

    void parseCommaList(
            const char *aStart,   // указатель на начало
            const char *aEnd,    // указатель на символ за концом
            char aComma,        // символ-разделитель
            bool aSkipEmpty,   // true, если пустые подстроки пропускать
            ProcParseCommaList aCallback,   // функция-нагрузка
            void *aData)   // этот параметр нужен, чтобы передавать какие хочешь данные в функцию-нагрузку, удаляй его смело!
    {
        str::trim(aStart, aEnd);    // моя функция; пододвигает aStart вперёд и aEnd назад, убирая пробелы.
                                    // Если удаление пробелов не нужно — удаляй! Если нужно — пиши сам.
        if (aStart == aEnd) return;
        const char *sstart = aStart;
        for (const char *p = aStart; p != aEnd; ++p)
        {
            if (*p != aComma) continue;
            const char *send = p;
            str::trim(sstart, send);   // то же самое, можно убрать
            if (p != sstart || !aSkipEmpty)
                aCallback(sstart, send, aData);    // замени на боевую нагрузку
            sstart = p + 1;
        }
        str::trim(sstart, aEnd);   // то же самое, можно убрать
        if (sstart != aEnd || !aSkipEmpty)
            aCallback(sstart, aEnd, aData);    // замени на боевую нагрузку
    }


    И, соответственно, версия для std::string.

    inline void parseCommaList(
            const std::string &aIn,
            char aComma,
            bool aSkipEmpty,
            ProcParseCommaList aCallback,
            void *aData)
    {
        parseCommaList(aIn.data(), aIn.data() + aIn.length(), aComma, aSkipEmpty,
                aCallback, aData);
    }
    Ответ написан
    Комментировать
  • Как добавить все элементы из вектора в контейнер multimap под определенный ключ?

    @Mercury13
    Программист на «си с крестами» и не только
    Если вам нужен именно multimap, другого способа я не вижу. Но если элементов много, стоит задействовать хинт (параметр position, где примерно элемент будет стоять). Что-то типа (в компиляторе не проверял, код почти гарантированно неверный).
    if (!names.empty()) {
        Users::const_iterator hint = users.upper_bound(1);
        for (auto &i :  names) {
          users.insert(hint, {1, i});
        }
    }

    Учтите, что при переходе с 03 в 11 поменялся смысл хинта, тут версия для 11.
    P.S. Извините, код для хинта можно сделать и проще. После вставки и ++ хинт останется тем же.
    Ответ написан
    Комментировать
  • Как корректно обрезать строку тип string в utf8 на с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Символов Юникода или байтов UTF-8?

    В любом случае байты UTF-8 делятся на три категории…
    • Начальные: 0x00…0x79, и 0xC0…0xF4
    • Дополнительные (не бывают в начале): 0x80…0xBF
    • Запрещённые: 0xF5…0xFF. В наших целях тоже можно отнести к начальным.

    Если задача — получить 10 символов, то находим 11-й начальный символ и обрезаем перед ним.

    Если задача — получить 10 байт и 11-й (s[10], если таковой есть, разумеется) — не начальный, начинаем урезать строку, пока не отрежем начальный символ.
    Ответ написан
  • Qt. Как передавать данные между формами?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариантов много, в зависимости от того, форма модальная или нет, и нужно ли каким-то моделям передавать сообщение «обновись».

    Вариант 1.
    class AddItem : public QWidget
    {
    public:
      AddItem(QWidget* aParent, QList<Institution>& aInstitutions)
          : QWidget(aParent), institutions(aInstitutions) {}
    private:
      QList<Institution>& institutions;
    };


    Во втором варианте у нас модальная форма, но редактировать можно только копию (например, институции первой формы задействованы в какой-то модели, или нужны каскадные удаления, или что-то ещё).
    class AddItem : public QDialog
    {
    public:
      int exec(QList<Institution>& aInstitutions);
    private:
      QList<Institution> institutions;
    };
    
    int AddItem::exec(QList<Institution>& aInstitutions)
    {
      institutions = aInstitutions;
      int r = QDialog::exec();
      if (r) {
         aInstitutions = std::move(institutions);
      }
      return r;
    }


    И много-много других вариантов.
    Ответ написан
    Комментировать
  • Qt как создать много окон внутри одного?

    @Mercury13
    Программист на «си с крестами» и не только
    Сам не работал с этим под Qt, но называется это «многодокументный интерфейс» и простейший пример тут.
    doc.qt.io/qt-5/qtwidgets-mainwindows-mdi-example.html

    Также можно погуглить «Qt MDI».
    Ответ написан
    1 комментарий
  • Почему возникает ошибка "Нет такого слота"?

    @Mercury13
    Программист на «си с крестами» и не только
    Иногда Qt Creator проглючивает и требуется полная перекомпиляция проекта.
    Почему-то не запустился MOC.
    Ответ написан
  • Зачем нужны матрицы в Direct3D?

    @Mercury13
    Программист на «си с крестами» и не только
    Начнём с того, что вектор имеет три координаты: x, y и z. Все повороты системы координат (x, y, z) → (x', y', z'), масштабирования и их комбинации можно записать в виде

    x' = a11·x + a12·y + a13·z
    y' = a21·x + a22·y + a23·z
    z' = a31·x + a32·y + a33·z

    А теперь прочитайте, что такое «умножить матрицу на вектор». Узнаёте? — матрицу {aij} размером 3×3 умножаем на вектор-столбец (x, y, z)T и получаем вектор-столбец (x', y', z')T. Здесь буква T — это операция «транспонировать матрицу», заменить строки столбцами, а столбцы — строками.

    А теперь сделаем финт ушами. Возьмём 4-векторы (r, s, t, d) и обозначим x=r/d, y = s/d, z = t/d (так называемые однородные координаты). Преобразование в однородные координаты неоднозначно: декартовы координаты (1, 2, 3) можно обозначить как четвёркой (1, 2, 3, 1), так и четвёркой (10, 20, 30, 10). Для чего нам однородные? Матрицы 4×4, работающие над однородными координатами, позволяют записать и такие преобразования, как «сдвинуть» или «центральная проекция». Например, «сдвинуть» записывается как

    r' = 1·r + shiftx·d
    s' = 1·s + shifty·d
    t' = 1·t + shiftz·d
    d' = d

    или, в терминах матриц
    [r']   ( 1 0 0 shiftx )   [r]
    [s'] = ( 0 1 0 shifty ) · [s]
    [t']   ( 0 0 1 shiftz )   [t]
    [d']   ( 0 0 0 1      )   [d]

    (тут я не поленился собрать тэгом code нечто похожее на вектор-столбец, так что знак транспонирования не нужен :)
    Ответ написан
    Комментировать
  • Для чего нужна рантайм-библиотека?

    @Mercury13
    Программист на «си с крестами» и не только
    В рантайм-библиотеке хранятся стандартные функции языка программирования. И malloc/new тоже.

    P.S. Также хранятся внутренние функции для обслуживания точки входа (int main).
    Ответ написан
  • Qt: как сделать, чтобы редактор в таблице вёл себя по-другому при нажатии Tab?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    QModelIndex EditableTable::moveCursor(
            CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
    {
        switch (cursorAction) {
        case QAbstractItemView::MoveNext:
        case QAbstractItemView::MovePrevious:
            return QModelIndex();
            break;
        default:
            return Super::moveCursor(cursorAction, modifiers);
        }
    }


    Чтобы протолкнуть такую функциональность в Qt Creator, использовать функцию «Promote To…»
    Ответ написан
    Комментировать
  • Почему не советуют использовать технологии Borland?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Очень долгое время был устаревший компилятор C++. Насколько мне известно, в XE10, совсем недавно, решилось (не проверял). Слоупоки!
    2. А почему? Где-то с 2001 года Borland натурально начхал на Delphi. Delphi 7 долгое время был самым лучшим — пока не появился 2010. Новые владельцы восстанавливают упущенное, но не всё идёт как надо (XE4 реально глючнее XE2, буду ещё думать, что лучше держать под Win10, чтобы работало с тамошней средой .NET).
    3. Кажется, они поставили не на тот кроссплатформенный фреймворк. FireMonkey — имитация стандартных элементов управления. Медленно и глючно. А если ради чего-то решил выключить ClearType — вообще атас!
    4. Бесплатный WinForms отобрал немалую аудиторию у тех, кому надо быстренько написать программу только под Windows. Но это скорее аналог VCL, чем FireMonkey.
    5. Embarcadero — фактически единственные, кто поддерживает хороший Паскаль.
    Ответ написан
    Комментировать
  • Есть бинарные дерево поиска в С++?

    @Mercury13
    Программист на «си с крестами» и не только
    Именно так работает стандартный контейнер std::map.
    Ответ написан
    Комментировать
  • Как в с++ добавить переменную в обьект уже определённого класса?

    @Mercury13
    Программист на «си с крестами» и не только
    Способ 1. Наследование.
    class Entity
    {
    public:
      virtual ~Entity() {}    // для корректной работы динамических структур данных 
                              // наподобие менеджеров уровней; в нашем примере не нужно;
                              // в реальной игре потребуется
    }
    
    class Player : public Entity
    {
    public:
       bool isDead;
    }
    
    int main()
    {
       Player player;
       player.isDead = true;
       return 0;
    }


    Если кто-то отдаёт Entity, окторый гарантированно Player — то
    Player& somePlayer = dynamic_cast<Player&>(someEntity);


    Способ 2. Композиция
    class Player
    {
    public:
       Entity entity;
       bool isDead;
    }


    Способ 3. Словарь. Это уже на случай, когда чужой код настолько монолитный, что ничем его не прошибёшь.
    struct PlayerInfo
    {
        bool isDead;
    }
    
    std::map<const Entity*, PlayerInfo> playerInfo;


    Если чужой код монолитный, а объекты ещё и перемещаются по памяти — тогда выяснить, что будет «значением» объекта (например, какой-нибудь идентификатор).

    typedef std::string PlayerId;
    std::map<PlayerId, PlayerInfo> playerInfo;


    Если и код монолитный, и «имя» или «значение» объекту никак не придумаешь — тогда никак.
    Ответ написан
    9 комментариев
  • Как присвоить переменную?

    @Mercury13
    Программист на «си с крестами» и не только
    Так, я был явно неправ, что язык — C++ Builder. Если это C++/CLI, то…
    String^ theLine = this->serialPort1->ReadLine();
    Вроде так.
    Ответ написан
  • Должно ли так быть?

    @Mercury13
    Программист на «си с крестами» и не только
    Ошибка у тебя в scanf.

    scanf("%lf",&x);

    %lg тоже работает — по крайней мере, на MinGW.

    Мало известно, но у scanf немного не такой формат подстановок, чем у printf.
    Ответ написан
    2 комментария
  • Почему не возможен синхронизованный вывод двух потоков при использовании двух мутексов?

    @Mercury13
    Программист на «си с крестами» и не только
    А точно нельзя?
    Я бы сделал так…

    Поток 1.
    мютекс2.войди
    поток2.старт
    повторяй 10 раз
      мютекс1.войди
      writeln
      мютекс2.выйди
    поток2.дождись
    мютекс2.выйди

    Поток 2.
    повторяй 10 раз
      мютекс2.войди
      writeln
      мютекс1.выйди

    Обратите внимание, мы входим в один мютекс и выходим из другого. Проверю, отпишусь.

    Единственное спорное «средство синхронизации» — в потоке 1 дождаться завершения потока 2.
    Ответ написан
    3 комментария
  • Что хранится в указателе на виртуальный метод класса в C++ Builder (содержимое __thunk__ )?

    @Mercury13
    Программист на «си с крестами» и не только
    Это сколько нужно байтов стека. В случае void* ничего возвращать не нужно. В случае int, char*, возвращаемое значение лежит в eax. В случае double — на верхушке стека сопроцессора. А в случае пользовательского класса — где-то в стеке вызовов. Класс Baz пустой, только указатель на ТВМ — потому 4 байта. Для класса Bar посмотри ради интереса sizeof — почти уверен, что те же 4 байта.
    Возможно, когда добавим локальных переменных, эта цифра тоже увеличится.
    Ответ написан
  • Как правильно передать в функцию ссылку на двумерный массив?

    @Mercury13
    Программист на «си с крестами» и не только
    void readResponses(string address, string (&rResponse)[15][4]) {}


    Двухмерный массив — НЕ указатели на указатель, это тебе не Ява. Это массив одномерных массивов.

    Нормального способа передачи массивов фиксированной длины в Си нет (только через ук-ль на первый элемент), в Си++ — через ссылку.
    Ответ написан
    6 комментариев
  • Является ли статическая функция С++ потокобезопасной?

    @Mercury13
    Программист на «си с крестами» и не только
    1. На что вам две статических переменных set?
    2. Не забудь, переменная статическая и находится в сегменте данных. Так что конструктор Settings() будет выполнен перед запуском main.
    3. Функция возвращает ссылку без const. Будут ли меняться настройки? Да — опасно почти гарантированно (структуры данных, потокобезопасные по записи — дело редкое и сложное). Нет — возвращай const Settings& и убедись, что все поля Settings также потокобезопасны по чтению (обычно ответ на этот вопрос да).
    4. А initializeDefaults() потокобезопасен? Скорее всего, нет.

    > Является ли вызов данной функции потокобезопасным?
    Нет однозначного ответа, скорее всего, нет.

    > Выполняется ли проверка File()::exists(settingsFilePath) при каждом обращении к функции?
    Выполняется.

    ЗЫ. Функция вот такого типа точно потокобезопасна — в ней просто нет объектов, за которые можно устраивать гонку.
    static inline Settings applicationSettings(){
        if (!File::exists(settingsFilePath)){
            Settings set(settingsFilePath);
            set.initializeDefaults();
            return set;
        }else{        
            return Settings(settingsFilePath);
        }
    }
    Ответ написан
    Комментировать
  • Какая разница между String& operator+ (); и String operator+ ();?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое возвращает по ссылке, второе по значению. Первое просто возвращает адрес, второе делает копию. Как определить, что нам нужно?
    Где у нас результат: в локальной переменной или нет?

    Перед нами операция «унарный плюс», которая, скорее всего, ничего не делает и return *this. Этот самый *this точно не локальный. Потому возвращаем по ссылке, String&.

    А теперь возьмём бинарное сложение. Мы создаём новую строку (как локальную переменную, разумеется), заносим в неё сумму… а чтобы она не исчезла раньше, чем её подберёт вызывавшая подпрограмма, вернём по значению (String).

    Для виртуальных функций обычно перестраховываются и возвращают по значению (String). Чхают на копирование, зато если вдруг потомку потребуется вернуть что-то локальное, он без проблем вернёт.
    class Father {
    private:
      String fName;
    public:
      virtual String& name() const { return fName; }  // пока всё нормально, но…
    };
    
    class Son : public Father {
    public:
      String& name() const
         { return Father::name() + "'s son"; }   // ошибка, возвращаем локальную переменную!
    };
    Ответ написан
    Комментировать
  • Как в узлы бинарного дерева вставить упорядоченный массив?

    @Mercury13
    Программист на «си с крестами» и не только
    Немного непонятно, для чего вам это нужно. Если это учебный код, то пишите по-студенчески. В промышленном коде я бы как можно больше пользовался проверенными функциями. Массив — std::vector, дерево сортировки — std::set/std::map.

    Сбалансированному упорядоченному бинарному дереву нужен ключ, по которому оно упорядочивает. Есть два варианта.

    1. Ключ — что-нибудь с естественным сравнением, например, int. Тогда std::map<int, std::vector<int> >.

    2. Ключ — тот самый массив. Тогда std::set<std::vector<int> >. (В предыдущей версии я явно писал механизм сравнения, оказывается, он уже есть и писать ничего не нужно!)
    Ответ написан
    Комментировать