Задать вопрос
Ответы пользователя по тегу C++
  • Тестовое задания - написать свой видео проигрыватель, сложно ли это?

    @Mercury13
    Программист на «си с крестами» и не только
    Не советую — эти ребята хотят чужими руками жар загребать.
    Слишком уж специализированная программа выходит — два монитора, эффекты частиц…
    Работы, как по мне, на два рабочих дня даже с наличием библиотек.
    Ответ написан
    Комментировать
  • Как пропусть внешний и внутрений цикл For?

    @Mercury13
    Программист на «си с крестами» и не только
    goto перед концом внешнего цикла.

    for(первый) {
      for(второй) {
        goto a;
      }
      a:;
    }
    Ответ написан
    Комментировать
  • Как это должно работать?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, ищите Hello World на WinAPI. Поскольку WinMain() там стандартный и немаленький, его опустили.

    Основано это на поведении Windows: она всегда пытается закрыть прогу корректно. Хорошо, закроем корректно, зато вот тебе вторая.
    Ответ написан
  • Как понять условие задачи?

    @Mercury13
    Программист на «си с крестами» и не только
    Что вы не поняли в решении: вы оптимизируете «чёрную» половинку графа, забыв, что самое малое ребро может быть в «белой».

    ДЛЯ КАЖДОЙ ВЕРШИНЫ: ук-ль на «начальника» + флаг инверсии. Если у вершины нет начальника — то указывает в null.
    ДИРЕКТОРОМ назовём вершину, у которого нет начальников. Считаем также, что у директора флаг инверсии всегда false.

    Заведём функцию getInfoNonDestructive, она возвращает структуру из двух элементов. Во-первых, это директор (никогда не null!!). Во-вторых, это цвет — XOR флагов инверсии от самóй вершины до директора.

    Функция getInfo вызовет getInfoNonDestructive, а затем проведёт ОПТИМИЗАЦИЮ СТРУКТУРЫ: ЕСЛИ вершина имеет начальника, ТО: начальник вершины := директор, флаг инверсии вершины := цвет вершины.

    СЛИЯНИЕ фирм происходит так. Директор фирмы становится подчинённым кому-то из членов другой фирмы.

    ИЗНАЧАЛЬНО для всех вершин начальник — null, флаг инверсии — false. То есть каждая вершина белая и сама себе директор.
    РЕШЕНИЕ: Отсортируем рёбра в порядке возрастания.
    Для каждого ребра…
    • Находим информацию о вершинах — концах ребра.
    • Если директор один и цвета разные — ничего не делаем.
    • Если директор один и цвет один — выводим вес этого ребра как ответ.
    • Если директора разные — сливаем фирмы. Подкручиваем флаг инверсии того директора, который исчез, так, чтобы цвета вершин — концов ребра были разные. Хотя бы так.
    VertexInfo info1 = getInfo(vertex1);
    VertexInfo info2 = getInfo(vertex2);
    if (…) {
      info1.director->superior = info2.director;
      VertexInfo info1new = getInfoNonDestructive(vertex1);
      if (info1new.color == info2.color)
        info1.director->inverseFlag = !info1.director->inverseFlag;
    }

    ВНИМАНИЕ, без оптимизации структуры сложность с «чуть более O(N)» превращается в N²! Но конкретно в этом месте важно получить инфу без разрушений — временно запрещается кого бы то ни было выводить из-под старого директора, пока не выставим ему флаг инверсии цвета.

    Если рёбер не осталось — перед нами двудольный граф, такого по условию не бывает.

    (такая структура данных, только без флага инверсии, называется, «система непересекающихся множеств»).

    ТЕОРИЯ. Начиная от самых «маленьких» рёбер, начинаем раскрашивать вершины в разные цвета. Если в какой-то момент это не удалось (цвета уже одинаковые) — выводим это ребро как ответ. Если соединяются два раскрашенных «островка» (в нашей терминологии «фирмы») — возможно, один из островков придётся инвертировать, и надо наладить инверсию так, чтобы она не захватила весь островок (судя по цифре 105, от нас ожидают сложность N log N, а не N²). Поскольку соединение кусков графа рёбрами и подсчёт компонент связности — это самая настоящая система непересекающихся множеств, я попытался приделать к этой самой СнПМ раскраску, не повышающую общую сложность (амортизированные почти что O(1) за транзакцию).

    Попробуй доказать самостоятельно, что данная система не зависит от того, в каком порядке оказались рёбра с одинаковым весом.

    И кончайте на чужом буе в рай въезжать!
    Ответ написан
  • Как линковщик производит подстановку функций из динамических библиотек?

    @Mercury13
    Программист на «си с крестами» и не только
    Это называется name mangling — как по-русски, я не знаю, но называю это «козявить имена».

    Названия foo в объектных файлах действительно не будет существовать.

    Линкер тут ни к чему, имена готовит компилятор. Потому, кстати, в межъязыковых библиотеках стараются имена не козявить.

    Чтобы функция называлась именно так, как надо, в Си++ есть ключевое слово extern "C", и часто его применяют, например, при экспорте в межъязыковой DLL, при интеграции Си-кода с Си++. Что в Ди, не знаю.
    В Си такого точно нет, как ты назвал, так и называются.

    Линкер, конечно, может каким-то образом подхватывать DLL (так работает LD), но это очень не стандартно — при переходе с LD на LLD пришлось готовить *.a для всех имеющихся DLL. Но в любом случае именами занимается компилятор.
    Ответ написан
    4 комментария
  • Почему программа на C++ не выводит результат?

    @Mercury13
    Программист на «си с крестами» и не только
    printf("%d %f", &n, &sum);
    printf("%d %f", n, sum);
    Ответ написан
  • В чем разница между методом в public и private?

    @Mercury13
    Программист на «си с крестами» и не только
    Это права доступа к методу. Относятся не к Cи++, а к ООП в целом.

    private — имеют доступ только методы самого объекта.
    protected — имеют доступ методы объекта и его потомков.
    public — кто угодно.

    Также существуют права доступа типа «не важно, что объекты станут связанным клубком; я готов к тому, что этот клубок придётся добавлять в программу целиком». В общем, когда объекты имеют доступ к private-методам друг друга.
    • В Си++ — ключевое слово friend
    • В Java — без ключевого слова (т.н. права доступа package)
    • В Паскале — по умолчанию есть доступ к private-полям и методам всех объектов в том же модуле.

    Эти особые права доступа (friend/package) оправданы, когда…
    • Издержки от клубка незначительны (например, объекты невелики и хорошо взаимосвязаны).
    • В клубок входят объект и его утилиты (например, какая-нибудь операция ++).
    Ответ написан
    Комментировать
  • Детерминирована ли реализация typeid?

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

    @Mercury13
    Программист на «си с крестами» и не только
    У вас нормальное (хоть и корявое по части кода, я за такой код пинаю!) лобовое решение. Очевидно, придётся наладить какой-нибудь ускоритель, позволяющий выполнить запрос быстрее, чем за O(n).

    Моё предложение: map (ради скорости можно прикрутить собственный аллокатор типа «объектный пул», благо кол-во блоков данных ограничено сверху 100k), показывающий, например, для третьего примера картинку «1→1, 2→2, 3→3, 4→4, 5→5». После первой транзакции — «1→2, 3→3, 4→4, 5→5». Поиск в этом map’е — upper_bound минус единичка (даже поиск 1-цы укажет или на второй элемент, или за первый). Сможете наладить методику разделения и склеивания диапазонов?

    Можно и наоборот: 2→1, 3→3, 4→4, 5→5. Поиск в таком map’е — lower_bound (даже поиск 5-ки не выкинет за пределы, правильно?).
    Ответ написан
  • Может ли процессор изменять порядок инструкций в программе?

    @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;
    }
    Ответ написан