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

    @Mercury13
    Программист на «си с крестами» и не только
    А там нет такого уж сложного анализа. Процессор преобразует каждую команду x86 в команду VLIW (Very Long Instruction Word — что делать каждому из блоков процессора), а затем пробует спрессовывать эти команды вместе. Насколько мне известно, первым на x86 такой механизм был предложен в процессоре Transmeta Crusoe, за пару лет до Intel.

    А ещё подобное налаживание зависимостей позволяет процессору делать что-то сразу же, а не ждать данных из медленной памяти. А ещё — патчить ошибки процессора :). Не помню, запатчили так Meltdown или нет.

    Подсистема памяти тоже может так работать — на x86 я не могу привести примеры, но представьте себе: одну строку кэша сбросило в память, а вторую держит.
    Ответ написан
    2 комментария
  • Зачем нужен MySQL Connector c++?

    @Mercury13
    Программист на «си с крестами» и не только
    MySQL Connector C++ — это совсем другая библиотека, с другой DLL’кой, подключающаяся на другой порт MySQL, по другому протоколу и работающая не со всеми версиями MySQL. И потому не слишком нужная.

    Вы задействовали MySQL Connector C, он действует, и пусть действует. Буквально две недели назад я написал свою поддержку MySQL, тоже через Connector C — именно потому что с совместимостью лучше. А поддержку Си++ написал самостийно, примерно так…

    class Res
        {
        public:
            Res() = default;
            Res(MYSQL_RES* x) : fD(x) {}
            Res(const Res&) = delete;
            Res(Res&& x) { operator = (std::move(x)); }
            Res& operator = (const Res& x) = delete;
            Res& operator = (Res&& x);
    
            ~Res() { close(); }
    
            const MYSQL_RES& d() { return *fD; }
            void close();
            bool next();
            std::wstring tableName() const;
            const char* at(size_t i) const { return fRw[i]; }
        private:
            MYSQL_RES* fD = nullptr;
            MYSQL_ROW fRw = nullptr;
        };
    Ответ написан
  • Производительность typedef?

    @Mercury13
    Программист на «си с крестами» и не только
    int64_t и long long — одно и то же.
    Компиляция ускоряется, потому что не подключается файл <stdint.h>, в котором наверняка больше строк, чем в основной вашей программе.
    На исполнение повлиять не должно.
    Ответ написан
    Комментировать
  • Где используются умные указатели?

    @Mercury13
    Программист на «си с крестами» и не только
    Давайте я для простоты расскажу только про unique_ptr. Вот у нас есть код.
    Obj* p = new Obj;
    …
    delete obj;


    Если мы забываем про delete, память начинает течь. Если мы делаем слишком ранний delete, мы обращаемся к удалённому объекту. И тут помогает главная фишка Си++ — автодеструкторы.
    u_p<Obj> p { new Obj };
    // И делай с ним что хочешь, удалится автоматически


    Вот несколько мест, где без u_p тяжело.

    1. Функция возвращает объект, а разрушить должен пользователь.
    u_p<ImportIssues> getImportIssues();

    2. Мы создаём объект виртуального класса и обращаемся к нему.
    class Father{
    public:
      virtual ~Father();
    };
    class Son : public Father{};
    class AnotherSon : public Father{};
    
    u_p<Father> someObj { new Son };


    3. Вообще работа с объектами, которые где-то появляются и где-то исчезают и потому приходится держать как указатели.
    std::vector<std::unique_ptr<QThread>> backJobs;
    Ответ написан
  • Как вернуть указатель на двухмерный массив?

    @Mercury13
    Программист на «си с крестами» и не только
    typedef bool SymbolBoolMap[16][15];
    static SymbolBoolMap symbol_Bool_Map_English_Upper_A = { ... };

    и возвращай [const] SymbolBoolMap&.

    Вообще есть два разных метода организации многомерных массивов: кусок памяти M×N и одномерный массив[M] указателей на массивы[N].
    Если для одномерных массивов кусок памяти длины N впрямую конвертируется в указатель (и даже при определённых условиях всё работает), то в многомерных первое и второе НЕСОВМЕСТИМЫ.
    Ответ написан
    2 комментария
  • Как передать двумерный массив в функцию без динамического выделения памяти?

    @Mercury13
    Программист на «си с крестами» и не только
    Для неизменяемых данных я придумал.
    #include <iostream>
    
    template <class T>
    struct Array
    {
        const size_t size;
        const T* const data;
    
        const T* begin() const { return data; }
        const T* end() const { return data + size; }
    
        constexpr Array(const std::initializer_list<T>& x)
            : size(x.size()), data(x.begin()) {}
    };
    
    using Row = Array<int>;
    using Matrix = Array<Row>;
    
    Matrix mtx = {
      {1, 2, 3 },
      { 10, 20, 30, 40, 50 },
      {},
      { 100 }
    };
    
    int main()
    {
        for (auto& u : mtx) {
            for (auto& v : u) {
                std::cout << v << ' ';
            }
            std::cout << std::endl;
        }
        return 0;
    }


    Для изменяемых данных пока вышло только так.
    #include <iostream>
    
    // Изменяемый вариант
    template <class T>
    struct Array2
    {
        const size_t size;
        T* const data;
    
        T* begin() { return data; }
        T* end() { return data + size; }
        const T* begin() const { return data; }
        const T* end() const { return data + size; }
        T& operator[](int i) { return data[i]; }
    
        template <size_t N>
        constexpr Array2(T (&x)[N])
            : size(N), data(x) {}
    };
    
    using Row2 = Array2<int>;
    using Matrix2 = Array2<Row2>;
    
    int main()
    {
        int i;
        std::cin >> i;
    
        int row1[] = { 1, i, 3 };
        int row2[] = { 10, 2*i, 30, 3*i, 50 };
        int row3[] = { 13 };
        int row4[] = { 100 };
    
        Row2 mtx[] = { row1, row2, row3, row4 };
    
        mtx[1][4] = i * 6;
    
        for (auto& u : mtx) {
            for (auto& v : u) {
                std::cout << v << ' ';
            }
            std::cout << std::endl;
        }
        return 0;
    }
    Ответ написан
    5 комментариев
  • Использование Hash в c++?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое — создать конструктором без параметров безымянный экземпляр класса и запустить ему операцию ().
    Второе — либо создать безымянный экземпляр класса конструктором с одним параметром, либо запустить шаблонную функцию.

    std::hash оформлено как struct, конструктор самый обычный, и есть операция () — потому первое.
    Ответ написан
  • Как реализовать кастомный тип данных в c++ без использования нативной системой типов?

    @Mercury13
    Программист на «си с крестами» и не только
    На самом деле такое возможно единственным методом: через ассемблерные вставки. Чем-нибудь типа
    mov ecx, [data]
    mov byte ptr[ecx], 5

    Штатные типы позволяют, в числе прочего, интерпретировать те или иные байтовые данные разными методами. Вернёмся к одному байту. Он может быть…
    • числом
    • восемью флагами
    • четырёхбитовым числом и четырьмя флагами
    Ответ написан
    Комментировать
  • Погрешность чисел в c++?

    @Mercury13
    Программист на «си с крестами» и не только
    #include <iostream>
    #include <iomanip>
    
    int main()
    {
        double q = 1.0 / 6.0;
        std::cout << std::setprecision(9) << q << std::endl;
        return 0;
    }


    Float не годится, поскольку не даёт такой погрешности.
    Ответ написан
    Комментировать
  • Как сделать графическую оболочку для консольного приложения?

    @Mercury13
    Программист на «си с крестами» и не только
    Вот мой код. Не законченный (завязанный на моей собственной библиотеке абстрактных потоков, не реализована функция flush, поток ошибок намеренно не перенаправлен), но относительно действующий.

    spoiler
    class ConStream : public st::Stream
    {
    public:
        ConStream();
        ~ConStream() override;
        bool open(
                const std::wstring& aFname,
                const std::wstring& aCmdLine,
                const std::wstring& aLog);
    
        // Console does not have remainder.
        st::Pos remainder() override { return 0; }
        // Only when we bumped into end.
        size_t eof() override { return fIsEof; }
        size_t readNe (void* aBuf, size_t aSize) override;
        size_t writeNe(const void* aBuf, size_t aSize) override;
        void flush() override;
        bool isOpen() override { return fIsOpen; }
    
        bool readln(std::string& s);
        void endInput();
    
        // Shall we implement close?
        //void close() override {}
    
        // Implemented capabilities
        unsigned long caps() const override
            { return st::cRead | st::cWrite | st::cMultiplex | st::cRealtime
                | st::cSizeUnaware; }
    private:
        st::AsyncFile fLog;
        bool fIsOpen = false;
        bool fIsEof = false;
        bool fFoundCr = false;
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
    
        HANDLE hStdOutInside, hStdOutOutside;
        HANDLE hStdInInside, hStdInOutside;
        //HANDLE hStdErrInside, hStdErrOutside;
        //bool readln(std::string& s);
    };
    
    
    ConStream::ConStream()
    {
        SECURITY_ATTRIBUTES sa;
          // Security attributes
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = nullptr;
        sa.bInheritHandle = true;  // Help says the handle will be inherited
    
        SECURITY_DESCRIPTOR sd;
        if (isWinNT()) {       // security initialization for Windows NT
            InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
            SetSecurityDescriptorDacl(&sd, true, nullptr, false);
            sa.lpSecurityDescriptor = &sd;
        }
    
        // Stdout pipe
        // read = outside, write = inside
        CreatePipe(&hStdOutOutside, &hStdOutInside, &sa, 0);
        SetHandleInformation(hStdOutOutside, HANDLE_FLAG_INHERIT, 0);
    
        // Stderr pipe
        // read = outside, write = inside
        //CreatePipe(&hStdErrOutside, &hStdErrInside, &sa, 1024*64);  // enough for stderr?
        //SetHandleInformation(hStdErrOutside, HANDLE_FLAG_INHERIT, 0);
    
        // Stdin pipe
        // read = inside, write = outside
        CreatePipe(&hStdInInside, &hStdInOutside, &sa, 1024*10);
        SetHandleInformation(hStdInOutside, HANDLE_FLAG_INHERIT, 0);
    }
    
    
    void ConStream::endInput()
    {
        if (hStdInOutside != INVALID_HANDLE_VALUE) {
            CloseHandle(hStdInOutside);
            hStdInOutside = INVALID_HANDLE_VALUE;
        }
    }
    
    
    ConStream::~ConStream()
    {
        if (fIsOpen) {
            if (WaitForSingleObject(pi.hProcess, 2000) == WAIT_TIMEOUT) {
                TerminateProcess(pi.hProcess, 0);
            }
    
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
        }
        CloseHandle(hStdInInside);
        endInput();
        //CloseHandle(hStdErrOutside);
        //CloseHandle(hStdErrInside);
        CloseHandle(hStdOutOutside);
        CloseHandle(hStdOutInside);
    }
    
    
    bool ConStream::open(
            const std::wstring& aFname,
            const std::wstring& aCmdLine,
            const std::wstring& aLog)
    {
        if (fIsOpen)
            return false;
    
        // Fill startup info
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        size_t n = aFname.length() + aCmdLine.length() + 10;
    
        si.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
        si.hStdOutput = hStdOutInside;
        si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
        si.hStdInput = hStdInInside;
        si.wShowWindow = SW_HIDE;
    
        std::wstring ws;
        ws.reserve(n);
        ws += L'"';
        ws += aFname;
        ws += L"\" ";
        ws += aCmdLine;
    
        fIsOpen = CreateProcess(
                nullptr,        // lpApplicationName
                &*ws.begin(),   // lpCommandLine
                nullptr,        // lpProcessAttributes
                nullptr,        // lpThreadAttributes
                TRUE,           // bInheritHandles
                0,              // dwCreationFlags
                nullptr,        // lpEnvironment
                nullptr,        // lpCurrentDirectory
                &si,            // lpStartupInfo
                &pi );          // lpProcessInformation
    
        if (fIsOpen && !aLog.empty())
            fLog.open(aLog.c_str(), st::File::omNew);
    
        return fIsOpen;
    }
    
    
    void ConStream::flush()
    {
    
    }
    
    
    size_t ConStream::readNe (void* aBuf, size_t aSize)
    {
        if (!fIsOpen)
            return 0;
    
        DWORD nRead;
        if (!ReadFile(hStdOutOutside, aBuf, static_cast<DWORD>(aSize), &nRead, nullptr))
            return 0;
    
        if (fLog.isOpen())
            fLog.write(aBuf, nRead);
    
        return nRead;
    }
    
    
    // Implemented write
    size_t ConStream::writeNe(const void* aBuf, size_t aSize)
    {
        if (!fIsOpen)
            return 0;
    
        DWORD nWritten;
        if (!WriteFile(hStdInOutside, aBuf, static_cast<DWORD>(aSize), &nWritten, nullptr))
            return 0;
        return nWritten;
    }
    
    
    bool ConStream::readln(std::string& s)
    {
        if (!fIsOpen)
            return false;
    
        s.clear();
        enum { SZ = 256, TIME = 30 };
        char buf[SZ + 2];
        DWORD nRead, nm1, nm2;
    
        while (true) {
            if (!PeekNamedPipe(hStdOutOutside, buf, SZ, &nRead, &nm1, &nm2))
                throwWinError();
            // Read nothing — maybe, the program has finished?
            if (nRead == 0) {
                if (WaitForSingleObject(pi.hProcess, TIME) == WAIT_OBJECT_0) {
                    // Try again
                    if (!PeekNamedPipe(hStdOutOutside, buf, SZ, &nRead, &nm1, &nm2))
                        throwWinError();
                    if (nRead == 0)
                        return !s.empty();
                    // otherwise fall out
                }
            }
            const char* start = buf;
            const char* end = buf + nRead;
            if (fFoundCr && *start == '\n') {
                ++start;
                fFoundCr = false;
            }
            for (const char* p = start; p != end; ++p) {
                switch (*p) {
                case '\r':
                    fFoundCr = true;
                    // fall through
                case '\n':
                    s.append(start, p);
                    // Read until CR
                    ++p;
                    skipRead(p - buf);
                    return true;
                default: ;
                }
            }
            // Copy the entire buffer and go on
            s.append(start, end);
            skipRead(end - buf);
        }
    }
    Ответ написан
  • Почему CharToOemW преобразует не все символы?

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

    inline const char* wtc(const WCHAR *from)
    {
      //Используется буффер -- статическая переменная
      static char buf[1024] = { 0 };
      size_t nChars = std::min<size_t>(wcslen(from), 1024 - 1);
      if (!CharToOemBuffW(from, buf, nChars)) {
        cout << GetLastError();
        exit(-1);
      }
      buf[nChars] = 0;
      return buf;
    }
    Ответ написан
  • Сколько бит(байт) занимают типы данных с плавающей запятой в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Например, int занимает 4 байта

    По современному консенсусу, да. Но иногда может занимать 2 байта (меньше — вроде нет).

    В случае с double можно задать абсолютно любое число

    double x = 1e500;
    Ответ статического анализатора Clang: magnitude of floating-point constant is too large for type 'double'; maximum is 1.79…E+308

    На число 1.23456789012345678901234 не жалуется, но учите матчасть — относительная точность double 52 двоичных цифры (исключая головную единицу), или около 16 десятичных.

    для чего в конце приписывают 'f' ,когда пользуются типом данных float?

    Чтобы расчёт float x; return x + 12.34f вёлся в менее точном типе float, а не double.
    А вот коду float x = 12.34; это совершенно не нужно, компилятор и сам поймёт, что преобразование double → float можно сделать при компиляции.

    Сколько бит(байт) занимают типы данных с плавающей запятой в C++?

    Зависит от машины, но по выработанному консенсусу — float 4, double 8.
    Нестандартная (присущая x86) реализация long double имеет 10 значащих байтов, но 12 или 16 вместе с выравниванием.
    Ответ написан
    Комментировать
  • Что означают данные строки?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами вариативный шаблон Си++11.

    Функция printTypes действует так. Для первого параметра подбираем подходящую перегрузку функции NameOf. Второй и далее — снова подставляем в функцию printTypes.

    types... t — это любое количество параметров любых типов. Которые, в свою очередь, можно рекурсивно подставить в шаблон printTypes.

    DEF_TYPENAME(float) — это использование препроцессора Си++ (никакой уже не 11), чтобы объявить несколько стандартных специализаций одного шаблона.
    Ответ написан
  • Как правильно называть переменные в заголовке функции (параметры или аргументы)?

    @Mercury13
    Программист на «си с крестами» и не только
    Одна сатана. В терминологии одних языков принято parameter, других argument.
    Ответ написан
    Комментировать
  • Почему нельзя передавать лямбду как аргумент шаблона?

    @Mercury13
    Программист на «си с крестами» и не только
    #include <iostream>
    
    template <class Body>
    void call(const Body& body) {
        body();
    };
    
    void test() {
      std::cout << "function" << std::endl;
    }
    
    int main() {
      call(test);
      call([]() {
        std::cout << "lambda" << std::endl;
      });
      return 0;
    }


    Дело в том, что лямбда — это объект неизвестного класса с операцией (). И только так её вызывают.
    Ответ написан
    1 комментарий
  • Правилен ли такой подход к разбиению C приложения на модули?

    @Mercury13
    Программист на «си с крестами» и не только
    Смотря в чём задача.
    Возможно, нет никаких проблем.
    Возможно, удастся вытащить общую функциональность в defines.h.
    Возможно, удастся каким-то образом разорвать порочный круг. Например, в ООП это можно делать через интерфейс.
    Ответ написан
    Комментировать
  • Как сделать так, чтобы CodeBlocks не ставил знаки?

    @Mercury13
    Программист на «си с крестами» и не только
    Settings → Editor → General Settings (стоит по умолчанию) → Editor Settings (стоит по умолчанию) → Indent Options → Brace completion

    5cfa263e49d5b731760499.png
    Ответ написан
    Комментировать
  • Исключение. Что это значит?

    @Mercury13
    Программист на «си с крестами» и не только
    Это значит: вы «сломали» память. Как правило, разыменованием «висячего» указателя или вылетом за пределы массива.
    Ответ написан
    Комментировать
  • Как вычислить интеграл с помощью формулы Симпсона?

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

    Первое, что нужно сделать,— вынести расчёт интеграла в отдельную функцию. Помимо прочего, она должна принимать параметром n — количество точек разбиения. И проверьте, разумеется, работоспособность.

    Затем поднимаемся на более высокий уровень — налаживаем алгоритм выдерживания точности. Я бы написал так.
    n := 10
    yНовое := расчёт(n)
    повтор
      n := n·2
      yСтарое := yНовое
      yНовое := расчёт(n)
    пока |yСтарое - yНовое| > эпсилон
    вывести/вернуть yНовое

    Сможешь перевести на Си?
    Ответ написан
    Комментировать
  • Почему Segmentation fault?

    @Mercury13
    Программист на «си с крестами» и не только
    Переменная run ничему не присвоена.
    Ответ написан
    Комментировать