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

    @res2001
    Developer, ex-admin
    Оба варианта правильные. Имя функции это и есть указатель на функцию, так что sizeof(foo) == sizeof(&foo). По сути тут компилятор просто игнорирует операцию взятия адреса от функции.
    Вся функция никогда не передается - только указатель.

    Я бы предпочел второй вариант, т.к. тут явно указано, что надо передавать указатель на функцию.
    На самом деле тип указателя на функцию я бы оформил через typedef, и в параметре указывал бы уже имя типа:
    typedef void (*foo_t)();
    void fooPrint(foo_t foo) {
        foo();
    }
    Ответ написан
    4 комментария
  • Как правильно записать в файл?

    @res2001
    Developer, ex-admin
    Для вывода в файл следует использовать объект ofstream. ifstream предназначен для чтения из файла.
    Для выравнивания, форматирования и т.п. смотрите модификаторы ввода/вывода: https://en.cppreference.com/w/cpp/io/manip
    Ответ написан
    Комментировать
  • Можно ли управлять всей программой с помощью скриптового языка?

    @res2001
    Developer, ex-admin
    Так же lua (как и другие скриптовые языки) можно встраивать в собственное приложение.
    Оба варианта имеют место быть, вопрос лишь в том кто главный и кто рулит тут всем.
    При использовании подхода из ответа shurshur главный - интерпретатор скриптового языка (и твое приложение, написанное на этом языке), а твоя С/С++ библиотека - один из модулей используемых скриптом.
    При встраивании главное твое приложение, которое может вызывать скрипты для каких-то своих целей. Скрипты могут использовать объекты твоей программы, для которых ты разрешил это действие.
    Выбор реализации во многом зависит от того, что хочется получить в итоге.
    Ответ написан
    Комментировать
  • По какой причине несовместимость библиотек?

    @res2001
    Developer, ex-admin
    Тут скорее причина не в "несовместимости", а в "cannot find -lcpprest: No such file or directory"
    Проверьте существует ли библиотека по указанному пути. Скорее всего ее нет.
    Надо разобраться почему ее нет. Я так понимаю, она должна собраться вместе со всем остальным.
    Может не хватает каких-то ключей для сборки и т.п.

    При сборке включите режим verbose и проверьте весь вывод make, есть ли там упоминание о сборке libcpprest.a
    Ответ написан
  • Ошибка mutex слишком много обращений к объекту?

    @res2001
    Developer, ex-admin
    Найдите тут подходящую под ваше описание ошибку
    https://linux.die.net/man/3/pthread_mutex_lock
    Я что-то не нашел.
    Единственный более-менее подходящий с натяжкой вариант - EAGAIN - возвращается в случае рекурсивного мьютекса при превышении максимального количества блокировок.

    В целом реализации мьтексов могут быть разные и если это не POSIX совместимая реализация, то вероятно такая ошибка возможна. В этом случае смотрите документацию к вашей системе.
    Ответ написан
    1 комментарий
  • Почему в СТЕКЕ разрешается выделять достаточно мало памяти?

    @res2001
    Developer, ex-admin
    Память на стеке в подавляющем большинстве случаев выделяется под переменные, зависимые от области видимости. Эти переменные с не большим временем жизни, а значит в большинстве случаев они не слишком большие и их можно смело выделить на стеке.
    Если у вас переменная с неопределенным временем жизни, то ее место в динамической памяти. Если ваша программа регулярно создает и уничтожает подобные переменные на большом временном промежутке, то стоит задуматься о реализации собственного аллокатора для подобных переменных, который бы один раз выделял память под относительно большой пул и уже из него отдавал программе куски памяти для размещения в них переменных.
    Кстати, в линуксе по умолчанию стек 8Мб, в винде 1Мб.
    Ответ написан
    Комментировать
  • Что нужно знать, чтобы написать web server на C++?

    @res2001
    Developer, ex-admin
    Полноценный веб сервер - это очень сложное ПО. Сам по себе протокол HTTP оброс кучей дополнений и улучшений, только посмотрите список RFC, его описывающих. В одиночку написать с нуля что-то подобное, например, apache - практически не посильное дело.
    Кроме HTTP, конечно, нужно хорошо знать и понимать сетевое программирование, параллельное программирование, английский язык, что-то еще.

    Но есть библиотеки, в которых веб сервер в каком-то виде с теми или иными ограничениями уже реализован. Можно использовать их. В этом случае задача сильно упрощается.
    Как пример: libonion, haywire, но это больше для Си. Для плюсов есть другие варианты.
    Ответ написан
    Комментировать
  • При выводе на экран одна строка копирует другую, хотя они должны быть разные. Как исправить?

    @res2001
    Developer, ex-admin
    Не копирует.
    У вас no - это объединение (union). В объединении все члены объединения занимают одну и ту же память, т.е. если вы посмотрите sizeof(no), то увидите 4 байта, т.е. память выделяется как для одного int, а у вас там 2 int. Т.е. то что вы написали в коде так оно и работает.
    Т.е. операции, например:
    f.a.people = 9;
    f.a.s = 2;

    перезаписывают одну и ту же область памяти. После этого f.a.people == 2, а не 9.
    Ответ написан
    Комментировать
  • Как исправить ошибку с построчным чтением из бинарного файла C++?

    @res2001
    Developer, ex-admin
    1. Хорошо бы код спрятать под тег code (есть кнопка в панели инструментов) и вернуть разметку, не возможно читать.
    2. Не видна последовательность вызовов input() и output().
    3. В input() файл открываете на запись, но ничего туда не пишете, в итоге файл пустой.
    4. В output вы не правильно читаете:

    Суть в том, что тип string хранит саму строку в динамической памяти, а не в самом объекте (в объекте только указатель на динамическую память). string у вас используется в AutoBase.
    Тем способом, которым вы пытаетесь читать из файла вы прочитаете какой-то указатель и скорее всего будет обращение к не выделенной памяти и программа упадет. Подозреваю, что запись вы бы реализовали так же и в файл записался бы указатель, а не строка.
    Вам надо читать и писать объект string по другому. Есть 2 варианта:
    • Сначала пишем/читаем размер строки, затем пишем/читаем саму строку заданного размера.
    • Пишем всю строку, в конце дописываем какой-то разделитель. В качестве разделителя можно использовать символ '\0', так же как в сырых Си строках или то что вам больше нравится, лишь бы разделитель не мог содержаться в самой строке. При чтении надо читать побайтно, до тех пор пока не встретится символ разделитель.

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

    @res2001
    Developer, ex-admin
    Читайте файлы сразу большими блоками (вплоть до всего файла сразу). Под большие блоки можете использовать std::vector<char> с предварительно установленным размером вектора (std::vector::reserve())
    Затем вручную делите прочтенный блок на строки, видимо, заменой \n на 0.
    Все указатели на найденные строки сразу складывайте в используемую в алгоритме структуру данных.
    Не используйте std::string, т.к. он реаллоцирует память на каждый чих, это приводит к повторному выделению того же самого объема памяти но порезанному на мелкие куски и дополнительному копированию строк. Используйте std::string_view (есть в С++17) или вообще сырые Сишные строки, как самый быстрый вариант.

    Вообще все массивы в плюсах (vector, array, "сырые" динамические и статические массивы) работают одинаково быстро, если рассматривать операцию обращения к элементу массива по индексу. Но в vectorе многие другие операции могут приводить к реаллокации памяти и копированию массива. В сырых динамических массивах вы не можете просто так изменить размер массива, это надо делать явно с помощью вызова realloc, а потому тут вы эту операцию явно контролируете, в векторах же (как и строках) это происходит не явно, поэтому часто разработчики не придают этому значения, тогда как обращения к менеджеру памяти достаточно дороги в плане производительности.
    Ответ написан
    Комментировать
  • Можно ли подменить WS2_32 библиотеку и есть ли готовая обёртка?

    @res2001
    Developer, ex-admin
    подумал может быть можно просто подменить эту библиотеку на свою?

    Просто положите свою библиотеку с таким же именем в каталог с программой.
    Виндовый загрузчик сначала исщет библиотеки в каталоге с запущенной программой и только потом по другим местам, указанным в PATH. Это касается и системных библиотек в т.ч.

    Но вам придется воспроизвести интерфейс WS2_32 и реализовать собственный эффективный механизм обмена.
    Если есть исходники приложения, то, возможно, будет проще изменить механизм обмена в самом приложении.
    Ответ написан
  • Какая книга по С++ мне лучше подойдёт?

    @res2001
    Developer, ex-admin
    Вам нужна книга, которую прочитаешь и сразу в "сеньоры" можно идти?
    Боюсь такой нет. Только практика и еще раз практика.

    Из продвинутых книг могу посоветовать:
    1. Эффективный и современный С++. 42 рекомендации по использованию C11 и C14
    в ней очень толково описаны нововведения в стандартах уже не совсем свежих, но эти нововведения чуть ли не самое главное изменение в языке до сих пор.
    2. Параллельное программирование на С++ в действии. Практика разработки многопоточных программ
    3. Оптимизация программ на C++. Проверенные методы повышения производительности.
    Ответ написан
    2 комментария
  • Какие внешние зависимости и как распологать в проекте?

    @res2001
    Developer, ex-admin
    Если проект для линукса (или другого никса), то лучше ставить зависимости из стандартных репозиториев, а не включать в проект. Если библиотеки в стандартных репозиториях нет, то уже возможны варианты.

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

    @res2001
    Developer, ex-admin
    Условия можно проверять с помощью enable_if.
    Переменную, видимо, придется запихнуть во вложенную шаблонную структуру, где и использовать enable_if.
    Я сам не силен в метапрограммировании, но можете начать по этой ссылке копать, там и примеров много.
    Ответ написан
    Комментировать
  • Есть ли аналог std::string в драйвере уровня ядра windows?

    @res2001
    Developer, ex-admin
    В WinAPI даже в user space нет аналога std::string.
    Что уж говорить о kernel space - там вообще все очень скудно.
    Перепишите функцию на использование Си строк и буфера фиксированного размера. Кроме того, загонять в драйвер функционал std::string видится избыточным - слишком много в stringе используется динамической памяти, что снижает производительность кода, обычно в драйверах это противопоказано.
    Ответ написан
    Комментировать
  • Важен ли return в main?

    @res2001
    Developer, ex-admin
    Если писать код, соответствующий стандарту языка, то корректно, конечно, указывать return.
    В большинстве современных ОС любой запущенный процесс возвращает код возврата. Это требование ОС. Кодом возврата процесса обычно является значение возвращаемое из main.

    Но, если код возврата не нужен, то можно не указывать return и объявлять void main(). Тогда считается, что код возврата из программы нулевой. Обычно это нормально отрабатывает. Но это не стандартная фича и ваша программа может не собраться на какой-то платформе и/или компиляторе.
    Ответ написан
    Комментировать
  • Как правильно выделить память (с проверкой выделения) для массива класса?

    @res2001
    Developer, ex-admin
    какой из вариантов наиболее эффективен / наиболее используемый

    Создание класса в динамической памяти делится на 2 этапа:
    1. выделение "сырой" памяти у менеджера памяти
    2. инициализация памяти - вызов конструктора класса на выделенном участке памяти.
    Вариант с malloc не выполняет вторую часть. Для того что бы закончить процесс в этом варианте вам надо использовать размещающий new, передав указатель на ранее выделенную память. Деструкторы так же нужно будет вызывать явно.

    Если вариант с malloc довести до логического конца, то он будет делать то же самое что и вариант с new, никаких преимуществ тут нет. Но не забываем про явный вызов деструктора.

    При удалении класса из динамической памяти присутствуют обратные этапы: вызов деструктора и освобождение памяти.

    malloc обычно используют в плюсовом коде, когда реализуют собственные аллокаторы и нужен "сырой" не инициализированный блок памяти. Но и в этом случае вполне можно обойтись без malloc - использовать new char[MEM_SIZE]
    Ответ написан
    Комментировать
  • Как использовать namespace в header?

    @res2001
    Developer, ex-admin
    Заверните весь код в input.cpp в namespace input {}
    namespace добавляет к символам в объектом файле имя namespace, но т.к. у вас определения в input.cpp не включены в namespace, то в объектном файле эти символа будут без добавления имени namespace, поэтому и undefined reference.
    Ответ написан
    Комментировать
  • Можно ли изменить размер типа int?

    @res2001
    Developer, ex-admin
    1. Размер всех типов всегда кратен 8 битам. Просто потому, что минимально адресуемый размер памяти в современных процессорах - это 1 байт. Так что 31 или 33 сделать не возможно. Теоретически можно сделать, например, 24 или 40, но смотри следующий пункт.
    2. Все базовые типы С/С++ однозначно проецируются на типы данных, поддерживаемые процессором. Поэтому реально использовать только типы, которые поддерживаются железом. А их не так много и все они, скорее всего, уже есть среди базовых типов С/С++.

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

    @res2001
    Developer, ex-admin
    Читайте тут до прояснения раздел "Bitwise shift operator.
    Смысл в том, что если вы знаковое число сдвинули влево так, что старшим разрядом стала 1, то в результате получится отрицательное число. При сдвиге вправо знакового числа, освобождающиеся слева разряды заполняются битом знака (а не нулем), поэтому результат сдвига отрицательного числа так же будет отрицательным (а положительного - положительным:). Если сдвигать вправо беззнаковое число, то свободные биты будут всегда заполнятся нулями.
    Кстати, на сколько помню, по стандарту знаковость char не определена (может быть как знаковым так и беззнаковым). Вам с вашим примером не повезло, char оказался знаковым. Зато это дало возможность немного глубже понять сдвиги.
    Ответ написан
    6 комментариев