Задать вопрос
Ответы пользователя по тегу C++
  • Почему адаптеры из range функторы?

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

    Если же это точка, где вы сами должны что-то дописать — что вам мешает сделать именно функцию? Функтор — это не только функция, а что угодно, что можно вызывать как функцию.
    Ответ написан
    6 комментариев
  • Почему bool оператор возвращает false, хотя на деле условия для true соблюдены?

    @Mercury13
    Программист на «си с крестами» и не только
    Стандартная ошибка наплюсника, аж две штуки.

    МАКРО-УРОВЕНЬ: вы пишете свою строку, но вместо того, чтобы сделать её отдельным объектом, инкапсулируете внутри Overcoat.

    Рисунок кода Си++ в точности обратный — всё, что умеет удерживать-отдавать ресурсы, переносится в отдельный объект небольшого размера. К тому же использование таких вот небольших объектов позволяет идиому «by-value+move»: если параметр — временная our::String, она просто переносится, а если нет — ну йок так йок.

    НЕПОСРЕДСТВЕННАЯ ПРИЧИНА: сравниваете указатели на буфера, а не содержимое строк.
    Ответ написан
    1 комментарий
  • Какая функция (или набор разных ф-ий) изменения "мощности" цвета света при распространении луча?

    @Mercury13
    Программист на «си с крестами» и не только
    Яркость лазера должна меняться с дальностью экспоненциально — яркость = A·e{Bx}: чем больше фотонов, тем больше рассеивается, дифур y’=−ky.
    Не забывайте, что sRGB сам нелинейный и состоит из линейного и степенного участка, но в целом неплохо приближается функцией y^2,2.
    Ответ написан
    Комментировать
  • Как синхронизировать процессы используя только std?

    @Mercury13
    Программист на «си с крестами» и не только
    Для чего нужен межпроцессный мьютекс? Для объекта (обычно куска памяти), который не проверяется на уровне системы и в то же время разделён между процессами.

    А в стандарте Си++ вообще такие объекты есть? Файлы проверяются. Каналы — насколько помню, нет стандартных, но они тоже проверяются.

    UPD3. Syncstream всё же содержит мьютекс, но второе решение — скопить данные в stringstream и сбросить их одной транзакцией — работает.
    Ответ написан
  • Не удаётся продолжить выполнение кода, поскольку система не обнаружила sfml-graphics-d-3.dll. Как исправить ошибку?

    @Mercury13
    Программист на «си с крестами» и не только
    Найти, где система сборки создаёт EXE. И положить рядом нужный DLL.
    Ответ написан
    Комментировать
  • Как подключить SDL к проекту C++?

    @Mercury13
    Программист на «си с крестами» и не только
    SDL3, MSYS…

    Обнови MSYS (SDL3 появился недавно)
    pacboy update (найди, какая там команда у pacman)

    pacboy sync sdl3:x
    (для pacman командную строку придумай сам)

    Вот CMake для первого примера SDL3
    cmake_minimum_required(VERSION 3.16)
    
    project(SDL3test LANGUAGES C)
    
    add_executable(SDL3test main.c)
    
    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    target_link_libraries(SDL3test PRIVATE SDL3)
    
    include(GNUInstallDirs)
    install(TARGETS SDL3test
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    )


    Автоматическое развёртывание я так и не смог прописать в CMake, придётся делать руками. Но хоть пускается.
    Ответ написан
  • Как cpp преобразовать в exe?

    @Mercury13
    Программист на «си с крестами» и не только
    Ищите этот файл в составе MinGW. Большинство сторонних DLL-библиотек используют данную библиотеку в виде DLL, но для отладки (например, если вылет на грани твоей программы и стандартной библиотеки), или если библиотек нет — можно его вставить в EXE.
    Ищите в системе сборки, как добавить ключи:
    в компилятор: -static-libgcc -static-libstdc++
    в линкер: -static -lpthread

    UPD. Вот я собрал мейкфайл. Он при сборке на MinGW будет собирать версию со статически прилинкованными библиотеками.
    cmake_minimum_required(VERSION 3.10.0)
    project(Game VERSION 0.1.0 LANGUAGES C CXX)
    
    if (MINGW)
        add_compile_options(-static-libgcc -static-libstdc++)
        add_link_options(-static -lpthread)	
        if (CMAKE_BUILD_TYPE STREQUAL "Release")
            add_compile_options(-O3)
            add_link_options(-s)
        endif()
    endif()
    
    add_executable(Game main.cpp)
    Ответ написан
  • Как решить ошибку bash: gdb command not found?

    @Mercury13
    Программист на «си с крестами» и не только
    Команда для обёртки pacboy:
    pacboy sync gdb:i gdb:x

    Команда для самого pacman:
    pacman --sync mingw-w64-i686-gdb mingw-w64-x86_64-gdb

    Команда для установки более удобного pacboy:
    pacman --sync pactoys

    И вообще освойте pacman или pacboy, очень много библиотек из MSYS (исключение: cURL) имеют удачную форму без лишних зависимостей.

    Попробуйте также пакет lldb, он может лучше работать, чем gdb.
    Ответ написан
  • Почему строку можно изменить через массив, но через указатель нельзя?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что в Си++ — в отличие от Си — строковый литерал "hello" имеет тип const char[]. Как дополнительную подсказку, что даже если система (скажем, DOS) не имеет разделения памяти по типам и позволяет менять такие литералы — Windows имеет и не позволяет.

    РАЗ. У указателя и массива несколько разная семантика
    char hello1[] = "hello";   // массив длины 6, в изменяемом сегменте или стеке,
                             // данные скопированы из литерала, который
                             // сидит в неизменяемом сегменте
    const char* hello2 = "hello";   // указатель направлен прямо на литерал,
                             // и попытка изменить его под Windows — вылет


    ДВА. Компилятор имеет право спрессовать два литерала в один, и смена одного, скорее всего, сменит и другой. Не могу проверить на Windows — говорил же, что запись в строковый литерал под Windows приведёт к вылету — но, скорее всего, так будет. Что-то вроде
    char* hello1 = const_cast<char*>("hello");
    char* hello2 = const_cast<char*>("hello");
    hello1[1] = 'U';   // hello2 = "hUllo" в системах вроде DOS, где не вылетит
    Ответ написан
    4 комментария
  • Почему объект не передается по ссылке?

    @Mercury13
    Программист на «си с крестами» и не только
    В BoxContainer, скорее всего, не происходит инициализация nbox.
    Поскольку NumberBox не имеет конструктора по умолчанию, компилятор ругается, что нельзя это поле инициализировать по умолчанию.
    Так что варианта два
    1. nbox инициализировать, наконец.
    BoxContainer::BoxContainer(NumberBox& nb) : nbox(nb) { ... }

    2. Придумать NumberBox конструктор по умолчанию
    class NumberBox {
    	...
    public:
    	NumberBox();
    	NumberBox(int i);
    	...
    };
    Ответ написан
    1 комментарий
  • Почему для добавления единичного бита используется именно 0x80?

    @Mercury13
    Программист на «си с крестами» и не только
    Мы обычно привыкли к порядку байтов в слове. Однако в криптографии и телекоммуникациях также играет роль порядок битов в байте — обычно у младшего бита номер 0, а у старшего 7. Это упрощает произвольный доступ к любому биту, передачу информации в порт по одному биту — я писал самодельные низкоуровневые коммуникационные протоколы, правда, давно и под DOS. Но тут, по-видимому, наоборот — байт начинается со СТАРШЕГО бита. Вижу в этом две причины.
    1. Межплатформенный стандарт двоичной передачи данных — передавать длинные числа, начиная со старшего байта, просто для удобства ручного исследования протоколов. Тут ручное исследование доведено до предела: байт делится на биты, которые также записываются от старшего к младшему — как мы бы записывали на бумаге.
    2. Криптографию по-чёрному оптимизируют, чтобы она оперировала не байтами, а самыми длинными единицами, доступными процессору: 64-битный — значит, блоками по 8 байтов.

    0x80 = 0b1000'0000. Вот вам и единичный бит и куча нулей.
    Ответ написан
    Комментировать
  • Расскажите пожалуйста как реализован sin в cmath?

    @Mercury13
    Программист на «си с крестами» и не только
    SET_RESTORE_ROUND_53BIT (FE_TONEAREST);
    Настройка сопроцессора. Это какая-то магия, имеющая две задачи: производительность и повторяемость.

    Дальше мы залезаем в устройство числа (причём для краткости имеем дело с 32-битными командами!) и проверяем на «малость» — если получилось малое, то sin x ≈ x.

    Дальше идёт проверка на |x|≲45° — идёт вычисление настоящего синуса. Опять-таки, проверка по верхним 32 битам числа (синус вычисляем по всем 64 битам ☺️).

    Если число не очень большое, мы загоняем его в диапазон ±45° и вычисляем синус или косинус.

    Если число побольше — идёт более злой загон в диапазон ±45° и то же самое.

    И последнее, что осталось,— ∞/NaN.

    Внутренние функции обозревать не буду, но что мы тут видим?
    1. Какие значения бывают чаще, какие реже?
    2. Для очень маленьких значений sin x ≈ x, cos x ≈ 1.
    3. Ещё одно — залезание во внутренний формат компьютерного дробного, причём даже на x64 имеем дело с 32-битными целыми.
    4. Даже функция приведения в ±45° есть в двух видах — упрощённом и «злом» в зависимости от абсолютной величины числа.
    Ответ написан
    4 комментария
  • Ошибка в вариативном шаблоне. Что не так?

    @Mercury13
    Программист на «си с крестами» и не только
    #include <iostream>
    #include <string>
    
    struct T {
        int x;
        std::string y;
    };
    
    T Deserialize(std::istream& stream, auto T::*... properties)
    {
        T object = {};
        auto FillObject = [&object, &stream] (auto property)
        {
            stream >> object.*property;
        };
    
        (FillObject(properties), ...);
        return object;
    };
    
    int main()
    {
        T r = Deserialize(std::cin, &T::x, &T::y);
        std::cout << "<" << r.x << "> <" << r.y << ">" "\n";
        return 0;
    }

    Что сделано: исправлен вызов FillObject (важно), уточнён тип properties (лучше).
    Ответ написан
    Комментировать
  • Как правильно организовать модули C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Не использую просто потому, что модули плохо устаканились. Посмотрел по MinGW — всё ещё экспериментальная функциональность.
    Для стандартных модулей: если поддерживаете Си++23, то пожалуйста. Это обычно главный источник медленной компиляции. Мой проект пока только 20.
    Для сторонних библиотек: можно прямо сейчас, если они собраны в модуль. Ни одной такой пока не видел, тем более в G++, как я сказал, это пока эксперимент.
    Для собственных модулей: убедитесь, что их поддерживает система сборки. В Си++26 усилят требования к модулям, потому что взвыли разработчики этих самых систем. И, как я сказал, в G++ модули — всё ещё эксперимент.
    Ответ написан
    Комментировать
  • Данные в таком случае будут хранится в стеке?

    @Mercury13
    Программист на «си с крестами» и не только
    Не пиши так, пожалуйста.
    Перед нами продление жизни временного объекта.
    Когда ссылка исчезнет — а она исчезнет после точки с запятой — указатель будет смотреть в никуда, и только от Ктулху зависит, когда переменную перезапишут.
    Правильно так:
    const int& ref = 1;
    const int* Number = &ref;

    Данные могут лежать где угодно — теоретически на стеке, но оптимизатор может перекинуть их и в сегмент данных.

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

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, перед нами конфликт первой и второй функции, и надо первую как-то ограничить.

    Вариант 1. Концепция Си++20.
    template <class T>
    concept Printable = requires(T x) {
            std::cout << x;
    };
    
    struct Class {
        template<Printable Text>
        Class& operator<<(const Text& text) {
            cout << text << endl;
            return *this;
        }


    Вариант 2. Обратная концепция.
    template<uint8_t i>
    struct Id {
        constexpr static uint8_t id = i;
        using SpecialPrint = void;
        // какие-то элементы класса с методами
    };
    . . . . .
    template <class T>
    concept SpecialPrintable = requires {
        typename T::SpecialPrint;
    };
    
    struct Class {
        template<class Text>
        Class& operator<<(const Text& text) {
            cout << text << endl;
            return *this;
        }
        
        template <SpecialPrintable Special>
        Class& operator<<(const Special& text) {
            specialPrint(text);        
            return *this;
        }
        
        template<uint8_t i>
        void specialPrint(const Id<i>& text) {
            cout << (int)i << endl;
        }
    };


    А на 17 без концепций…
    template<uint8_t i>
    struct Id {
        constexpr static uint8_t id = i;
        using SpecialPrint = void;
        // какие-то элементы класса с методами
    };
    . . . . .
    
    template<class T, class Dummy = void>
    struct IsSpecPrintable { static constexpr bool value = false; };
    
    template<class T>
    struct IsSpecPrintable<T, typename T::SpecialPrint> { static constexpr bool value = true; };
    
    struct Class {
        template <class T>
        Class& operator<<(const T& text)
        {
            if constexpr (IsSpecPrintable<T>::value) {
                specialPrint(text);
            } else {
                normalPrint(text);
            }
            return *this;
        }
    
        template<class Text>
        void normalPrint(const Text& text) {
            cout << text << endl;
        }
    
        template<uint8_t i>
        void specialPrint(const Id<i>& text) {
            cout << (int)i << endl;
        }
    };
    Ответ написан
    1 комментарий
  • Как работает массив?

    @Mercury13
    Программист на «си с крестами» и не только
    Массив — это отдельный тип, но он конвертируется в указатель. Мало того, в Си передача массивов в функции возможна только через указатель.
    Потому *array — это превратить в указатель, разыменовать, и будет ССЫЛКА на 0-й элемент.
    array+1 — это конвертируем в указатель, сдвигаем на единичку
    А *(array+1) — ссылка на 1-й элемент.
    Ответ написан
    Комментировать
  • Почему не запускается программа на Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Похоже на некорректные DLL. И, по-моему, виноваты DLL Си++ — обычно это творится, если используют сторонний компилятор (свежий Си++ дорогого стоит), а библиотеки из Qt.
    Ответ написан
  • Почему parentWidget возвращает nullptr?

    @Mercury13
    Программист на «си с крестами» и не только
    Простите, что пишу с опозданием.
    Потому что в Qt есть два «родителя».
    Родитель, отвечающий за уничтожение, и родитель в иерархии окон.
    Это вы объявили, кто автоматически уничтожит окно. А тут ещё надо someParent->addWidget(someChild);.

    В Delphi это названо owner и parent соответственно.
    Ответ написан
    Комментировать
  • Нормально ли создавать пустую вирутуальную функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    ВСЕ ПРИМЕРЫ ЖИВЫЕ, у меня перед глазами.
    • stream.flush — физический сброс данных на устройство (при выводе) или сброс буферов (при вводе) имеет место только с реальным устройством, а написанные прикладным прогером потоки редко с ними работают, потому пустая.
    • Импортёр из системы управления предприятием, который для каждого, например, рецепта производства вызывает callback. Если рецепты не поддерживаются — ничего не делать.
    • В каком-то виджете Qt напрочь убираем реакцию на колесо мыши.
    • Программа использует для ускорения кучу кэшей, которые перед импортом данных выкидываются. Если выкидывать нечего — функция compactMemory пуста.
    • Или твоя фигура-квадрат, для которой поворот ничего не делает.
    Ответ написан
    Комментировать