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

    @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> >. (В предыдущей версии я явно писал механизм сравнения, оказывается, он уже есть и писать ничего не нужно!)
    Ответ написан
    Комментировать
  • Как исправить ошибку collect2.exe: error: ld returned 1 exit status?

    @Mercury13
    Программист на «си с крестами» и не только
    На довольно давней версии mingw, имевшейся у меня, получилось сделать вот так — запустив компилятор и линкер раздельно.

    PATH %PATH%;d:\MinGW\x86\bin
    g++ -fopenmp -c main.cpp -o main.o
    g++ -o test.exe main.o -lgomp
    pause

    Заодно пришлось скачать pthreads для win32, по умолчанию библиотеки (*.a) есть, а dll нет.

    И вообще, это зависит от сборки MinGW. На свежих сборках mingw-w64 — как с Win32-, так и с posix-потоками — всё заработало именно по-твоему. И pthreads нашёлся.
    PATH %PATH%;d:\MinGW\i686-5.2.0-win32-dwarf-rt_v4-rev0\mingw32\bin\
    g++ -fopenmp main.cpp -o test.exe
    pause

    Ну и, конечно, ты не указал, ПОЧЕМУ линкер вышел с кодом 1. Но это я уже сам понял, поэкспериментировав.
    Ответ написан
    Комментировать
  • Для чего же нужны указатели?

    @Mercury13
    Программист на «си с крестами» и не только
    Хорошо, попробую. Вот у нас есть файл на каком-нибудь NAS. Мы хотим его переслать товарищу. Мы можем…
    • приложить файл к сообщению, тогда у нас будут два независимых файла. Просто и надёжно, недостатка два. 1) Файл копируется, это трудоёмко. 2) Копия живёт своей жизнью, и изменения в копии не затронут оригинал. Это передача по копии.
    • дать имя файла. Один изменяет файл — второй прочитает изменение, и никакого копирования. Недостаток — надо договариваться, кто владеет файлом (т.е. уничтожит его, когда тот не будет нужен). Имя файла — это и есть указатель.
    Метафора неполная, ведь файловая система может сказать, есть ли файл, а в памяти указатель на отсутствующий «файл» — это Access Violation. Да и «учёток» в памяти нет. Тем не менее…
    Ответ написан
    Комментировать
  • Как разобрать матрицу трансформации на состовляющие?

    @Mercury13
    Программист на «си с крестами» и не только
    Как я понял, твоя матрица 3×3 — это однородные координаты в 2D? Я бы поступил так.
    1. Убедиться, что элементы 3-1 и 3-2 нули (иначе — это не аффинное преобразование).
    2. Элемент 3-3 превратить в единицу, соответственно увеличив остальные (на что — читай, что такое однородные координаты).
    3. Элементы 1-3 и 2-3 — перенос. Отрежем их, получается матрица 2×2.
    4. То, что осталось, должно быть вида (c, s), (-s, c). Если с какой-то погрешностью это не так и 2-норма строк не единица (тоже с какой-то погрешностью) — это не поворот (т.е. может быть масштабирование или наклон). Остаётся взять atan2(c, s) — получается угол.
    Ответ написан
    Комментировать
  • Задача по методу Эйлера, за что отвечает функция F в данном коде?

    @Mercury13
    Программист на «си с крестами» и не только
    Качество кода — на уровне студенческой лабораторной. Причём очень хреновой.

    Программа решает четыре системы.
    y = f0(t)
    y' = f1(t, y)
    y'' = f2(t, y, y')
    y''' = f3(t, y, y'')

    1. Если уж говорить о методе Эйлера — в программе ошибка.
    y[1] = y[1] + delt * y[2];
    Тут нужно старое значение y[2], а не новое.

    2. Функцию eiler стоило бы обозвать eulerStep, заодно убрав лишние параметры.

    3. Автор не знает такой концепции, как процедурный тип aka callback, поэтому работа с правой частью у него вышла вот через такую задницу.

    4. В промышленном коде метод решения ОДУ я бы вынес в отдельную процедуру, с callback’ами на правую часть и на потребителя результата. Причём внешнее (доступное пользователю библиотеки) именование должно быть такое, чтобы её пользователь мог ею воспользоваться, даже если он не читал статью, по которой библиотеку писали. Так что смотрите, какие имена являются стандартизированными, понятными по любому учебнику, а какие стоит прояснить. Внутреннее именование — это уж думайте сами, научный код обычно сложен, и его постоянно приходится сличать со статьёй. Поэтому имена как в статье — для научного кода не WTF.

    5. Не слишком удачно разделена ответственность между функцией правой части и функцией шага по Эйлеру. Это привело к ограничению — программа может решать только ОДУ y{n} = f(t, y, y', ..., y{n−1}).
    Ответ написан
    8 комментариев
  • Надо решить проблему с include?

    @Mercury13
    Программист на «си с крестами» и не только
    Учи понятие «единица компиляции».

    Два варианта.
    a) Несколько единиц компиляции (основной вариант, когда идёт активная разработка проекта). Тогда в хедере каждую переменную отмечаешь модификатором extern — «переменная есть, но где-то в другом месте». В одной из единиц компиляции объявляешь переменные, уже без extern.

    Насколько мне известно, защита от двойного включения для extern-переменных не важна, но, например, для классов или функций ой как пригодится.

    ///// unit.h /////
    #ifndef UNIT_H
    #define UNIT_H
    
    extern int myVar;
    
    #endif
    
    ///// unit.cpp /////
    #include "unit.h"
    
    int myVar;
    
    ///// main.cpp /////
    #include "unit.h"
    
    int main()
    {
       myVar = 1;
    }


    б) Одна большущая единица компиляции (в такой вид часто преобразуют библиотеки перед выпуском). Тогда достаточно оградить каждый хедер от двойного включения, и всё в порядке.

    ///// unit.h /////
    #ifndef UNIT_H
    #define UNIT_H
    
    int myVar;
    
    #endif
    
    ///// main.cpp /////
    #include "unit.h"
    
    int main()
    {
       myVar = 1;
    }


    ЗЫ. Когда я писал ответ, кода ещё не было. А тут он взял и пришёл. Для переменных (SYMBOL_WIDTH, LINE_HEIGHT) решение то самое. А для констант вариантов несколько.

    Путь сишный.
    #define LEFTPANEL 200
    ВОЗМОЖНО для литеральных констант, и особенно классно работает с текстовыми строками (например, "[" TEXT "]").
    НЕДОСТАТКИ: это препроцессор, и при пересечении имён будет нехорошо.

    Путь перечислимый.
    enum {
      LEFTPANEL = 200
    };
    ВОЗМОЖНО для констант, влезающих в int.
    НЕДОСТАТКИ: возможны приколы с кроссплатформенностью, если на отдельных платформах константа вылезет за грань int.

    Путь переменный.
    extern const int LEFTPANEL;
    ....
    const int LEFTPANEL = 200;
    ВОЗМОЖНО для любых констант.
    НЕДОСТАТКИ: нет вычисления при компиляции. Только линкер знает, что это 200.

    Путь C++11.
    constexpr int LEFTPANEL = 200;
    ВОЗМОЖНО для литеральных констант.
    НЕДОСТАТКИ: только C++11.

    Путь «на рывок»
    static const int LEFTPANEL = 200;
    ВОЗМОЖНО для всех литеральных типов, но при этом может создавать дублирующиеся переменные: так, в Borland будет дублироваться всё сверх int — и, соответственно, не допускать предкомпилированных заголовков, ибо создаётся код.
    НЕДОСТАТКИ: семантика зависит от компилятора и типа, ради чего и сделали constexpr.
    Ответ написан
    2 комментария
  • Как избавиться от зависания формы при выполнении работы в потоке через Synchronize?

    @Mercury13
    Программист на «си с крестами» и не только
    Как ни странно, не использовать Synchronize на долгих операциях! Сабж выполняет операцию в главном потоке и, значит, главный поток всё это время не отвечает.

    Использовать какую-то структуру данных, в которую главный поток не лезет и надобности в синхронизации нет. А синхронизировать нужно только переключение состояния: поток работает или можно лезть.

    Можно использовать PostMessage, правда, никто не знает, когда форма подберёт сообщение и нужно чётко следить за тем, кто чем владеет.
    Ответ написан
    Комментировать
  • Для чего нужен данные предикаты?

    @Mercury13
    Программист на «си с крестами» и не только
    Попробую рассказать.

    Некоторые поисковые функции STL требуют для работы функцию. Например, www.cplusplus.com/reference/algorithm/find_if или www.cplusplus.com/reference/algorithm/sort (второй вариант).

    А что делать, если какие-то параметры поиска или сортировки задаются программно? Можно, конечно, эти параметры сделать глобальными переменными — но, как известно, «избегайте незнакомых женщин и глобальных переменных». В таком случае используют т.н. функтор — некий объект с операцией (). Другими словами, его «вызывают», как функцию. Все изменяемые параметры будут храниться в полях этого объекта.
    Ответ написан
    Комментировать
  • Почему ругается на дружественную функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    Причина, вероятно, в том, что ты допустил код в хедере, и sort_pred оказался реализован дважды в разных единицах компиляции.
    Либо сделай sort_pred inline (inline кода не производит, производит его тот, кто этот inline вызовет), либо вынеси его в cpp-файл.

    Ах, да. Почему всё правильно с этой функцией…

    bool operator()(two *t)
    {
        return t->getA()==a;
    }


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

    @Mercury13
    Программист на «си с крестами» и не только
    Что я пока вижу.
    1. В любой высокоуровневой библиотеке CreateThread использовать ЗАПРЕЩЕНО, вместо этого используй beginthreadex (или что-то ещё, предоставленное библиотекой). Или, раз уж ты по-чёрному используешь VCL, особо не убудет, если будешь использовать TThread.
    2. Lock и Unlock — это обыкновенный мьютекс. Все конкурирующие потоки, кому захочется рисовать на холсте, ждут и курят, ничего не делая.
    3. Самое-то главное ты упустил. Если ждёшь помощи, не нужно так секретничать, что не поймёшь, в чём дело. Где — хотя бы примерно — тело потока, и что делается в главном потоке?
    4. А как надо работать? Есть некая структура данных, в которой мы возвращаем из потока обработанные картинки, и volatile bool isWorking, который отвечает за то, работает поток или нет. Когда этот флажок false, главный поток имеет право работать с нашей структурой. Он переключается в true — в структуре может быть любой мусор, обращаться к ней запрещено! Если ещё и надо предупредить, когда поток закончился и можно забирать информацию — TThread.Synchronize или PostMessage. То и другое работает только в GUI-программах, если консольная — то через события (CreateEvent).
    5. А почему «нельзя этого делать»? Если партия приказала, значит, надо. Просто многопоточность — это тяжёлое дело, ошибки на каждом шагу, но «принципиально нельзя» — нет такого.
    Ответ написан
    4 комментария
  • Почему получается странная кодировка в файле?

    @Mercury13
    Программист на «си с крестами» и не только
    msc.insert(dat);
    Перед этой строчкой dat правильный, проверь?

    Если правильный — возможно, виновата ваша коллекция.
    Ответ написан
    1 комментарий
  • Странная кодировка в файле,с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Причина у тебя другая.

    char* — это просто указатель на чей-то другой отрезок памяти. И программист должен чётко осознавать его время жизни. Скорее всего, строка исчезла раньше, чем указатель. Используй автоматические строки наподобие std::string.

    Кроме того, std::map будет, если я не ошибаюсь, сортировать по адресам, а не по строкам. Чтобы всё работало, надо писать свою операцию <, читай документацию, как.
    Ответ написан
    6 комментариев
  • Как инициализировать строку PCHAR в с++?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Что принимает система: PCHAR или PCHAR*?
    2. Если версии Delphi достаточно новые, PCHAR — это, скорее всего, wchar_t* и надо просто передавать «широкую» строчку L"usb3000".
    3. Постарайся, чтобы reinterpret_cast не было; это признак того, что ты делаешь что-то неверно. Единственное, где он в подобных API допустим — это в callback’ах для передачи замыкания (информации о том, какая подпрограмма и при каких обстоятельствах запустила функцию, вызвавшую callback). P.S. Надумал и второе назначение reinterpret_cast — функция, которая может принимать данные разных типов (вроде SendMessage из Win32).
    Ответ написан
    Комментировать