Ответы пользователя по тегу C++
  • Как задать свойство класса экземпляром другого класса, если его значения не известны при инициализации?

    @Mercury13
    Программист на «си с крестами» и не только
    center_pt = *new Point(x/size, y/size);
    Утечка памяти. Никто в «си с крестами» за вас не будет подчищать все эти new.
    Правильно:
    center_pt = Point(x/size, y/size);
    (Ну и, разумеется, я не понимаю, что значат эти x/size и y/size, но шут с ним.)

    Примерно таким образом и происходит переприсваивание объектов, если им оставили таки операцию =. То есть…
    class Geolocator {
    public:
      Point coords;
      bool isReliable;
    
      Geolocator() : coords(0,0), isReliable(false) {}
    
      void getFromSensor() {
        coords = Point(100, 100);
        isReliable = true;
      }
    };


    Вариант 2. Через указатель, создание и уничтожение. Для простоты не буду это делать «руками», а воспользуюсь указателем единоличного владения unique_ptr.
    class Geolocator {
    public:
      std::unique_ptr<Point> coords;
    
      void getFromSensor() {
        Point pt(100, 100);
        if (coords) {
          *coords = pt;
        } else {
          coords.reset(new Point(pt));
        }
        // а если и операции = у Point нет, то можно
        // coords.reset(new Point(100, 100));
      }
    
      void declareUnreliable() {
        coords.reset();
      }
    };
    Ответ написан
    6 комментариев
  • Не заканчивается программа?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что конец консоли с клавиатуры зависит от ОС, и для Windows это Ctrl+Z.
    Нажатие ввода не передаёт в поток EOF.
    Ответ написан
    6 комментариев
  • Ввывод сообщения об успешном завершении программы в с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Вопрос в буферизации потоков ввода-вывода. Разумеется, на Windows и OSX эти подробности устроены по-разному. Два модификатора, std::endl и std::flush, сбрасывают буфера.
    cout << "Кол-ва нат чис: " << std::flush;
        cin >> n;
        
        cout << sum(n) << std::endl;
    Ответ написан
    Комментировать
  • Можно ли число представить в виде float?

    @Mercury13
    Программист на «си с крестами» и не только
    Float содержит 23 бита мантиссы и неявную единицу. Порядок float запредельный и даже qword не упрётся в него.
    Это значит: всё, что дальше 23 бит от верхней единицы, должно быть нулём.

    bool isPreciseFloat(unsigned long long n)
    {
      // Простейшая проверка: стираем нижние 24 бита
      // Если в них вписываемся — ДА.
      unsigned long long n1 = n & ~((1ULL << 24) - 1);
      if (n1 == 0)
        return true;
    
      // Получаем верхнюю единицу
      // (можно также двоичным поиском, но я этого с листа не напишу)
      while (true) {
        unsigned long long n2 = n1 & (n1 - 1);
        if (n2 == 0)
          break;
        n1 = n2;
      }
    
      // Получаем маску всего, что ниже 23 бит от верхнего бита.
      n1 >>= 23;
      --n1;
    
      // Проверяем по маске
      return (n & n1) == 0;
    }


    Писал «с листа», могут быть ошибки.
    Ответ написан
  • Иероглифы вместо кириллицы в с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами UTF-8. Перекодируйте исходник в рабочую кодировку (обычно DOS-866 или Windows-1251).

    Или работайте в широких строках. У меня на MinGW 5.3 получился вот такой исходник.
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        setlocale(LC_ALL, "rus");
        wcout << L"Превед!" << endl;
        return 0;
    }
    Ответ написан
  • Почему неправильный вывод значений в printf?

    @Mercury13
    Программист на «си с крестами» и не только
    У меня вышло: 0 1074266112 0 1074266112
    Или, в 16-й системе, 0 40080000 0 40080000

    Связано это с такими вещами.
    1. Аргументы типа float записываются в стеке как double.
    2. На x86 порядок байтов Intel (обратный).
    3. Дробные числа хранятся без ведущего разряда (который всегда 1), в формате мантисса-порядок-знак (на порядке байтов Intel).
    4. Для единицы (xxx·20) порядок будет 011…11.

    3 = 1,10…02·2¹, и с учётом отброшенного ведущего разряда мантисса будет 10…0.
    Порядок 011…11 + 1 = 10…0.

    С учётом обратного порядка байтов double 3,0 будет выглядеть так
    • 6 нулевых байтов — мантисса
    • 0000.1000: нижние полбайта — это мантисса, верхние — уже порядок
    • 0100.0000: бит знака и ещё семь битов порядка

    Получается 00.00.00.00.00.00.08.40.
    Разбиваем на два куска памяти по 4 байта.
    [00.00.00.00] [00.00.08.40]
    Опять-таки не забудем, что у целых тоже обратный порядок байтов — и получается 0 и 40080000.
    Ответ написан
    Комментировать
  • Почему не переполняется float?

    @Mercury13
    Программист на «си с крестами» и не только
    Представьте, у нас десятичная арифметика с тремя значащими цифрами. Соответственно, сложение работает не более чем с пятью цифрами: три собственно значащих, слева на перенос и справа на округление. То, что получилось, в любом случае будет округлено до трёх.
     99900000000000
    +             1,00
     -----------------
     9990   →   9,99e13

    Если сделать второе слагаемое покрупнее, то будет
     99900000000000
    +   50000000000
     -----------------
     9995   →   1,00e14 → переполнение


    То есть вот что надо добавить, чтобы случилось переполнение: в зависимости от настроек сопроцессора или ulp(FLT_MAX) (ULP = Unit of Last Place — цена младшего разряда на данном порядке), или ulp(FLT_MAX)/2.
    Ответ написан
    Комментировать
  • Зачем std::forward иметь две сигнатуры и явно указывать тип?

    @Mercury13
    Программист на «си с крестами» и не только
    std::forward предназначен для использования в шаблонах; без шаблона можно использовать старый добрый std::move.
    Кроме того, std::forward налажен таким образом, что шаблонный параметр надо указывать явно.

    Задача std::forward — передать далее простую или временную ссылку в зависимости от того, какую ссылку передаёт пользователь.
    Ответ написан
    6 комментариев
  • Написать программу, сильно тормозящую Windows?

    @Mercury13
    Программист на «си с крестами» и не только
    Много дёргать ввод-вывод. Например, помногу, в несколько потоков, читать диск.
    Если винт механический, Windows становится абсолютно неюзабельной.
    Ответ написан
    Комментировать
  • Как установить OpenCV для C++ в QT Creator?

    @Mercury13
    Программист на «си с крестами» и не только
    LIBS += -LC:/opencv/pro/lib -lxxx

    xxx — это имя файла с расширением a, без расширения и префикса lib.
    Если он libopencv_core.a, то надо -lopencv_core
    Ответ написан
    Комментировать
  • Почему запускается первым конструктор mainwindow.cpp?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы переписал архитектуру программы.
    1. Перед вами модальное окошко. Вот его и вызывайте, как модальное — au.exec().
    2. Чтобы проверить, что авторизация верна, надо соединиться. Так что сделайте невизуальный объект «соединение» и протащите в exec. Ну или создайте в exec.
    3. А уж там собирайте основную программу.
    QApplication a(argc, argv);
    FmAutoriz au;
    std::unique_ptr<SomeConnection> connection = au.exec();   // SomeConnection и exec придётся написать
    if (connection) {
      FmMain m(connection);
      m.show();
      return a.exec();
    } else {
      return 0;
    }
    
    std::unique_ptr<SomeConnection>FmAutoriz::exec()
    {
      bool b = QDialog::exec();
      if (b) {
        return std::move(this->connection);
          // connection — поле FmAutoriz.
          // Такой же unique_ptr, в обработчиках кнопок пытаемся создать соединение.
      } else {
         return nullptr;
      }
    }
    
    void FmAutorize_on_btOk_click()
    {
       connection = new SomeConnection();
       if (connection.connect(someLogin, somePassword)) {
          accept();
       } else {
          // сообщи об ошибке
       }
    }

    Вижу побочку этого (но, может, и не надо избавляться) — на панели задач анимацией сменяется кнопка с диалогом авторизации на кнопку с главным окном.
    Ответ написан
  • Как получить кол-во записей, которые помещаются в окне QTableView?

    @Mercury13
    Программист на «си с крестами» и не только
    Это на самом деле сложная задача, и я её решил вот так.
    QHeaderView* header = ui->tableView->verticalHeader();
    QWidget* viewport = header->viewport();
    int i1 = header->logicalIndexAt(0);
    int i2 = header->logicalIndexAt(viewport->height() - 1);
    if (i2 < 0)
        i2 = header->count() - 1;
    QString s = QString::number(i1) + " - " + QString::number(i2);
    ui->lbResult->setText(s);


    Если в очень упрощённом виде — то немного не так.
    return m_tableView->viewport()->height() / m_tableView->rowHeight(0);
    Ответ написан
    Комментировать
  • Приложения корректировки форматирования кода?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое. Нужен сильно упрощённый синтаксический анализ, который делит код на директивы препроцессора, лексемы, операторы и комментарии, понимающий вложенность операторных скобок.
    Второе. Все эти лексемы выкидываем в выходной поток, добавляя незначащие символы по всоему усмотрению.
    Третье. Комментарии тоже придётся переформатировать, и с этим отдельный геморрой.
    Для Си — там есть ещё #define. Идеал — развернуть каждый #define, добавив спецсимволы «тут начало #define», «тут конец #define», форматнуть код, передвинуть левый спецсимвол как можно правее по незначащим символам (а правый — как можно левее), а потом опустить всё между спецсимволами, оставив только #define в том виде, как он был.
    Ответ написан
    Комментировать
  • Variadic template c++?

    @Mercury13
    Программист на «си с крестами» и не только
    Этот шаблон вычисляет при компиляции такое:
    rbv<false, false, true, true>() = 11002.

    И состоит из двух частей.
    1. Для одного параметра у нас напрямую написан шаблон.

    2. Для false, false, true, true — у нас используется второй шаблон: a=false, b=false, d = (true, true).
    И он равняется (rbv<false, true, true> << 1) + false.

    Чтобы вычислить новый rbv, снова работает второй шаблон: a = false, b = true, d = (true).
    И он равняется (rbv<true, true> << 1) + false.

    Для третьего rbv у нас a = true, b = true, d = ().
    Внимание, список d может быть и пусттым. Потому, чтобы не было конфликта с первым шаблоном, второй пишется для двух и более параметров.
    И третье наше значение равняется (rbv<true> << 1) + true.

    Вот тут работает первый шаблон и получается 112.
    Дальше уже можно вычислить все rbv по очереди и получить 11002.
    Ответ написан
    4 комментария
  • Как запросить число через cin в C++ чтобы оно заканчивалось на цифру 5?

    @Mercury13
    Программист на «си с крестами» и не только
    Это невозможно, мэн волен ввести в консоль что угодно.
    Но ваша задача как программиста — каким-то образом не допустить некорректного ввода. То ли вывести ошибку, то ли самостийно округлить, то ли потребовать повторный ввод… Вы уж сами думайте, что требуется именно от вашей программы.
    Условие «кончается на 5» эквивалентно  «не делится на 10, но делится на 5».
    Ответ написан
  • Как работает данная программа C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Это обычная учебная программа и я за такой код бил бы по рукам. Нарекания к ней.
    1. Одновременное пользование printf и cout. Впрочем, несмотря на глючность, printf — хорошая штука, я и сам сделал более мощный аналог.
    2. Есть немного случаев, когда допустимы такие названия переменных/функций.
    • для счётчика цикла (i, j, k для переменной, it, jt, kt для итератора, u, v, w для новой фичи Си++11 — того, на что итератор указывает);
    • если мы преобразуем научную статью в код, и переменные так названы в статье.
    3. Даже название Count слишком расплывчатое — лучше что-то вроде nFound.
    UPD2. 4. Я бы переписал функцию P так, что for [0…горизонталь), при бое return false, цикл удался — return true.
    5. В музей говнокода!
    if (i == k)
        return true;
      else if (i != k)
        return false;
      else
        return !true && !false;

    Верно
    return (i==k);

    Программа проходится по 1-й горизонтали и ставит ферзя на каждую клетку. Если поместился — рекурсивно делает то же самое для 2-й горизонтали, если нет — значит, не повезло. Как только расчёт дойдёт до N-й горизонтали — мы нашли расположение ферзей, можно выводить.

    UPD. Ну, допустим, я бы переписал 2-ю функцию так (не меняя порядок параметров).
    void Backtracking(int currX, int &nFound, int boardSize, int queenY[])
    Ответ написан
    5 комментариев
  • Как правильно использовать строки в плюсах?

    @Mercury13
    Программист на «си с крестами» и не только
    • std::string — как правило, если не указано противное.

    • QString, AnsiString/UnicodeString и прочие — в соответствующих фреймворках, обычно очень близко к интерфейсным функциям.

    • char* — практически не используется в реальном коде. В основном для оптимизации, если есть собственное управление памятью. Довелось как-то в собственном разборщике XML (работает в 2,5 раза медленнее рекордсмена, pugixml. Зато даже это в разы быстрее Excel’я, пространства имён «из коробки», расход памяти мизерный и программирование простейшее.)
    Зато по-чёрному используется его const-аналог.

    • const char*. Это может быть одинокий const char* + нуль-терминированная строка, или указатель+длина, или указатель на начало + указатель за конец.
    1. Если ожидается, что в функцию будем передавать строковый литерал.
    void writeEnum(st::Stream& st, int value, const char* names[]) {}
    
    enum class Letter { A, B, C, …, Z, NN };
    const char* natoNames[static_cast<int>(Letter::NN)] = { "alpha", "bravo", "charlie", … };
    writeEnum(someStream, static_cast<int>(Letter::E), natoName);

    2. Если операцию со строкой можно произвести «на месте», не заводя новую память: (trim, как известно,— обрезка пробелов в начале и конце)
    void trim(const char*& beg, const char*& end);

    3. Если структура данных паразитирует на чужих строках, не заводя своей памяти. Особенно если конструкция строк неизвестна (например, при передаче данных из плагина в плагин).
    struct ParasiteString { const char *beg, *end; };

    4. В библиотеках, если они реально настолько компактные, что нет нужды обязательно подключать жирный STL.

    • char[] — только как оптимизация, когда предельная длина строки известна и невелика.
    wchar_t* myFtos(double value, wchar_t* buf, const FloatFormat& format) {}
    
    wchar_t buf[100];
    myFtos(100.500, buf, FloatFormat::NICE);
    Ответ написан
    Комментировать
  • Как упаковать файл в проект и затем извлечь на C++ в Visual Studio?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть три способа хранения картинки в EXE-файле.
    1. Bitmap-ресурсом. Несжатая, большинство библиотек позволяют загрузить её в одну строчку.
    2. Двоичным ресурсом. Сжатие возможно любое, загрузка пишется несколько дольше.
    3. Массивом, const unsigned char picture[] = { };

    Я не знаю, с какой библиотекой для BMP вы работаете, и надо смотреть уже по месту.

    И наконец: для чего её распаковывать? Реально нужно? (Например, мне однажды нужно было распаковывать картинки, потому что не хотел писать просмотрщик графики и пользовался штатным.)
    Если нужно — то куда-нибудь во временный каталог, который тоже нужно сначала получить.
    Ответ написан
    4 комментария
  • Как создать полностью пустое приложение на С++ в QT Creator?

    @Mercury13
    Программист на «си с крестами» и не только
    Простой способ (говорят, что есть глюки!)
    import QtQuick 2.9
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
        flags: Qt.Window | Qt.FramelessWindowHint   // <<<<<<
    
        Text {
            id: text1
            x: 77
            y: 59
            text: qsTr("Test!!!")
            font.pixelSize: 12
        }
    }


    Сложный описал Александр Таратин, и в нём эти глюки решены.
    Ответ написан
    Комментировать
  • С++ В чем отличие #include "*" и #include?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое — это include собственного заголовка, то есть искать его в рабочем каталоге, в дополнение к стандартным каталогам компилятора.

    #include <file>
    This variant is used for system header files. It searches for a file named file in a standard list of system directories. You can prepend directories to this list with the -I option (see Invocation).

    #include "file"
    This variant is used for header files of your own program. It searches for a file named file first in the directory containing the current file, then in the quote directories and then the same directories used for <file>. You can prepend directories to the list of quote directories with the -iquote option.
    Ответ написан
    Комментировать