Ответы пользователя по тегу C++
  • EventLoop, потоки и блокировки, как правильно блокировать?

    @res2001
    Developer, ex-admin
    Что касается ImageMemoryCache: в методе get вы возвращаете ссылку на элемент мапы. Блокировка с мапы снимается при выходе из get, но вызывающий код имеет ссылку и может с этим объектом делать все что угодно.
    Параллельно вы можете вызвать clear, который удалит элемент на который осталась ссылка в другом потоке.

    По уму вы должны блокировать мапу до тех пор пока жива любая ссылка на содержимое мапы.
    Второй вариант - создавать в get копии объектов из мапы и возвращать их. При этом изменение этого нового объекта никак не повлияет на объект в мапе. Ну тут можно что-нибудь придумать, сделать какой-то прокси объект и т.п.
    Третий вариант - каждый объект в мапе защищать своим мьютексом.
    Ответ написан
  • Создание файла txt и запись в него C++?

    @res2001
    Developer, ex-admin
    Смотри сначала сюда: https://en.cppreference.com/w/cpp/io/basic_fstream
    Потом сюда: https://en.cppreference.com/w/cpp/io/basic_filebuf/open
    fstream открывает файл по умолчанию (как у тебя) в режиме in|out, а это значит, что если файла не существует, то возникает ошибка (смотри таблицу по второй ссылке). Логика такая, что если ты открываешь файл для чтения (тут не важно, что он открывается еще и для записи) без дополнительных флагов, то файл должен существовать.

    В пару с ifstream, который открывает файл для чтения, существует и ofstream - он открывает файл для записи. При использовании ofstream не существующий файл будет создан (смотри таблицу по второй ссылке).
    Ответ написан
    Комментировать
  • Высвободится ли память,если использовать метод clear() у vector,который был заполнен структурами?

    @res2001
    Developer, ex-admin
    В С++ структура это практически то же самое что и класс.
    Реализуйте в структуре деструктор, в котором будет освобождаться память под name. При удалении элементов в векторе (clear), для каждого существующего элемента будет вызван деструктор.
    Ответ написан
    Комментировать
  • Что такое указатели в С++?

    @res2001
    Developer, ex-admin
    Из всего написанного по сути сказано только:
    Указатель — это переменная, хранящая в себе адрес ячейки оперативной памяти

    остальное - какой-то шлак.

    Добавлю от себя про указатели:
    Память в компьютере адресуется побайтово.
    Биты внутри байта адресовать через указатель нельзя.
    Адрес - это просто беззнаковое целое число - номер байта в памяти.
    В 32битных процах максимально доступно 2^32 байта памяти, в 64битных - 2^64.
    Соответственно для хранения адреса в 32битных системах нужно 32 бита, т.е. 4 байта, в 64битных - 64 бита, т.е. 8 байт. Таким образом, в зависимости от разрядности процессора меняется размер указателя.

    Когда некий объект (строка, число, и прочее) сохранен в памяти он не имеет типа - это просто набор байт некоторой длины. Типизацией занимается программа. Например в процессоре существуют наборы арифметических команд для целых 1 байтовых переменных, 2 байтовых, 4 и 8 байтовых (отдельно для знаковых и беззнаковых). Т.е. это реально разные ассемблерные инструкции (например для сложения). Таким образом задавая тип указателя, вы говорите компилятору, что к памяти, адресуемой этим указателем, нужно применять инструкции для этого типа данных.
    Для типизированных указателей можно использовать адресную арифметику, потому что компилятору известен размер типа. Для не типизированных указателей (void*) адресная арифметика не возможна.
    Ответ написан
    Комментировать
  • Я написал программу на c++, но при установке ее на другой копьютер выпадает ошибка MSVCP140D.dll, что делать?

    @res2001
    Developer, ex-admin
    Я предполагаю, что в папку с приложением нужно разместить библиотеки c++.

    Да вы верно думаете. Но делать надо не так.
    Ошибка возникает потому, что в С++ вы, как правило, используете хотя бы STL - а это внешняя библиотека и она должна быть доступна программе во время запуска.
    Но можно собрать программу со статической линковкой с STL, тогда размер исполняемого файла вашей программы будет больше, но тащить за собой ничего не придется.
    В принципе, динамическая линковка с STL - это нормально. Только в случае с программой собранной в MSVC вы должны предоставить пользователю еще и runtime пакет нужной версиии. Микрософт предоставляет эти сборки runtime отдельно от MSVC (можно скачать с сайта). Этот же установщик рантайма лежит где-то в недрах установленной MSVC, можно его там найти при желании.

    Цифры в имени файла dll (140) - это и есть версия нужного вам рантайма. Версия 140 или 14.0. Она идет с MSVS 2015.
    Вот тут статья с перечислением всех актуальных версий рантайма и ссылками на них: https://www.itechtics.com/microsoft-visual-c-redis...
    Ответ написан
    Комментировать
  • Почему в c++ можно задавать статический массив переменной длины?

    @res2001
    Developer, ex-admin
    Это потому что вы компилируете с помощью gcc.
    Вообще в стандарте С++ VLA (variable length array) нет в принципе и это ошибка.
    Но VLA есть в C99 и далее. А gcc с параметрами по умолчанию разрешает использовать расширения, в т.ч. и VLA.
    Стоит включить более строгое соответствие стандарту, как вы получите ошибку и не собираемый код.

    Рекомендую это (включать строгое соответствие стандарту) делать в своих проектах всегда. А так же включать вывод всех предупреждений (-Wall -Wextra) и пытаться добиваться сборки без предупреждений.
    Наиболее "продвинутые" переводят все предупреждения в ошибки, что бы программа в принципе не собиралась с любыми предупреждениями. Это то же делается соответствующей опцией компилятора.
    Часто в таких случаях приходится некоторые предупреждения ставить в игнор, но это делается всегда осознанно, с пониманием для чего это нужно.
    Ответ написан
    3 комментария
  • Как подсчитать необходимый размер буфера для monotonic_buffer_resource?

    @res2001
    Developer, ex-admin
    Например, в std::vector определяется тип value_type - это как раз тип элемента вектора.
    Можете использовать конструкции типа:
    sizeof(decltype(vector_val)::value_type)
    или
    sizeof(decltype(vector_val.back()))

    для вычисления размера элемента вектора, где vector_val - существующий экземпляр вектора
    Ответ написан
  • Как можно передать ссылку/адрес на относительно большой файл из go в c++?

    @res2001
    Developer, ex-admin
    А если скачанный файл будет размером в гигабайты. Куда вы денете такой файл в памяти? По моему это не правильная стратегия.

    Вы можете использовать shared memory для предоставления доступа к файлу. Но вам еще надо дать знать внешней программе, что память готова для ее обработки. А так же после обработки внешняя программа должна дать знать вашей программе, что она свою работу закончила. Тут уже не обойтись без механизмов IPC: каналы, именованные каналы, unix сокеты, eventfd, обычные сокеты, ...
    Но если внешняя программа будет запускаться из вашей программы как дочерний процесс, то можно просто ждать завершения процесса. Но процесс может завершиться аварийно, так что надо анализировать код возврата, который процесс должен обязательно вернуть.
    Ответ написан
    1 комментарий
  • Почему возникает ошибка C1014 "Too many include files: depth 1024"?

    @res2001
    Developer, ex-admin
    Поставьте первой строкой в заголовке
    #pragma once
    Возможно это избавит вас от ошибки.

    И зачем вы делает
    #include "Graphic_Library.cpp"
    не понятно.
    Это может говорить о том, что интерфейс, подключаемый в заголовочном файле вы не доработали, или какие-то другие ошибки. Подобная конструкция, конечно, не является ошибкой сама по себе, но, как правило, так не делают.
    Ответ написан
  • В чем отличие оператора -> от .(точки)?

    @res2001
    Developer, ex-admin
    Стрелка используется с указателями на класс/структуру, а точка со ссылками или с непосредственно экземпляром класса/структуры. Т.е. если вы попытаетесь использовать точку с указателем - получите синтаксическую ошибку.
    Ответ написан
    Комментировать
  • Есть ли где чёткая инструкция по работе с библиотекой sqlite для C++?

    @res2001
    Developer, ex-admin
    Черт знает где вы ищите. На сайт sqlite пробовали заходить?
    Для ВСЕХ инструментов типа баз данных есть родные (от производителя инструмента) клиентские библиотеки как минимум для Си. Т.к. эта библиотека открывает возможности для использования инструмента на любых других ЯПах. Нет смысла создавать инструмент, которым не возможно пользоваться.
    Для плюсов, как правило, делают легкую обертку над Сишной библиотекой, поддержка остальных ЯПов подтягивается потихоньку.
    SQLITE: https://www.sqlite.org/cintro.html
    Ответ написан
    8 комментариев
  • Из за чего в консоли вместо русского языка выводятся вопросительные знаки?

    @res2001
    Developer, ex-admin
    Это практически первый вопрос, которым задаются юниоры С++, когда пытаются запустить свою первую консольную программу под виндой.
    Ответов на него тут уже была целая пачка.

    Суть в том, что в виндовой консоли может быть 2 русские кодировки (cp866 и cp1251) (не уверен, но может быть консоль винды научилась уже нормально работать с UTF8, если научилась, то считайте, что добавилась еще одна кодировка). Причем по умолчанию используется cp866. Кодировку консоли можно менять из самой консоли или программно.
    При выводе текста в консоль никаких преобразований кодировок не происходит. В какой кодировке у вас написаны исходники - та и выводится. И если кодировка консоли и кодировка исходников не совпадают, то будет не читабельный текст.

    Самый оптимальный и самый сложный вариант - в программе узнать кодировку консоли и перед выводом конвертировать текст в эту кодировку. Так же обратную операцию производить при вводе. В этом случае исходники программы лучше всего писать в UTF8 и использовать wchar_t.

    Самый простой, дебильный и не всегда работающий (не будет работать если изменена кодировка консоли) - писать исходники в cp866.
    Немного чуть более сложный, но не правильный - поменять кодировку консоли из программы на ту в которой написаны исходники.

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

    @res2001
    Developer, ex-admin
    Отличный вопрос!

    Проблема есть, но она немного в другой плоскости, которую вы не упомянули - наследование. Т.е. например у вас иерархия классов с одним базовым классом и вы решаете хранить в массиве базовые классы, надеясь, что через базовый класс с помощью виртуальных методов выйдете на функционал наследников.
    Так не получится, т.к., действительно, в массиве все объекты имеют одинаковый размер и если вы создаете массив базовых классов, то размер элемента массива будет равен размеру экземпляра базового класса. Так что все экземпляры классов наследников урежутся при помещении в массив.

    Как эта проблема решается в с++?

    С++ не решает эту проблему. Эту проблему решаете вы как программист.
    Самое простое что приходит в голову - хранить в массиве не сами объекты, а указатели на них или ссылки.
    Так же было бы не плохо запретить возможность создавать экземпляры базовых классов, тогда у вас в принципе не будет возможности создать подобный массив.
    Ответ написан
    Комментировать
  • Как работает эта рекурсия?

    @res2001
    Developer, ex-admin
    По идее в foo с одним параметром перед return нужно добавить строку:
    std::cout << sizeof(value) << std::endl;
    Тогда будут выводится все параметры.
    Смысл рекурсии в том, что на каждом шаге выводится первый параметр и убирается из списка, обрезанный список параметров передается дальше по рекурсии. Пока параметров несколько вызывается функция со списком, когда параметр становится один (последний), вызывается foo с одним параметром и рекурсия завершается.
    Сейчас у вас foo с одним параметром не выводит ничего, поэтому последний параметр как бы игнорируется.
    Ответ написан
    Комментировать
  • Пишу кейлоггер на c++ и встретился с ошибками. Как их пофиксить?

    @res2001
    Developer, ex-admin
    Там где у функций WinAPI на входе параметр типа xxxWSTR - значит она ждет от тебя wchar_t, а не обычный char.
    Для большинства функций WinAPI работающих со строками есть 2 варианта одной и той же функции, один вариант принимает char, другой вариант wchar_t. Внутри винды используется wchar, так что есть смысл и в своих программах всегда использовать wchar, что бы избежать дополнительных преобразований.
    Ответ написан
  • Как присовить WCHAR* константное значение?

    @res2001
    Developer, ex-admin
    Объявите массив
    WCHAR targetWindowName[]
    и скопируйте туда свою константу используя, например, std::wcsncpy
    Ответ написан
    Комментировать
  • Где хранится nullptr? Для разных программ она разная?

    @res2001
    Developer, ex-admin
    nullptr - сам по себе это константа (сейчас не важно ее реальное значение). Где хранится, например, 2 или 100500?
    Вот когда вы сделаете присваивание:
    void *ptr = nullptr;
    То в указателе ptr будет хранится значение nullptr.
    Если посмотрите асемблерный код подобного присваивания, то там будет что-то вроде:
    mov ax, 0;
    В данном примере считаю, что значение nullptr - это 0. Тут видно, что nullptr хранится прямо в коде и является одним из операндов ассемблерной команды mov.
    Про то что хранится в памяти, куда указывает nullptr (и ptr из примера), написал Mercury13
    Ответ написан
    Комментировать
  • Есть ли механизм работы с сокетами в C++?

    @res2001
    Developer, ex-admin
    Ни в одном языке нет подобных функций. Просто потому, что это API операционной системы, а ОС, обычно пишут на Си. Но даже в Си их нет - это функции ОС.
    Но полно библиотек, которые оборачивают ОС API в классы. Пользуйтесь. Их достаточно много. Хорошие варианты привел @gbg

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

    @res2001
    Developer, ex-admin
    Числа с плавающей точкой по определению приближенные. Каждая операция над подобными числами вносит свою погрешность в результат. Так что не стоит удивляться. В какую сторону и на сколько будет погрешность, думаю, это можно посчитать, но для этого надо копнуть глубже.
    Для проверки можете просто вывести результат 2 сложений, потом трех, ... А так же проверьте результат умножения.
    Тут много интересного можно для себя открыть.
    Так же небезъинтересно сравнить результат одних и тех же вычислений над double и float.
    Даже и не надейтесь в плавающей точке получить какой-то точный результат. Если нужна точность, то надо использовать фиксированную точку.
    Ответ написан
    Комментировать
  • Где то слышал что префиксный инкремент работает быстрее чем постфиксный. Это так?

    @res2001
    Developer, ex-admin
    Не замерял скорость. И даже не смотрел в дизасемблере реализацию.
    Но предлагаю просто разложить обе операции на примитивные ассемблерные инструкции (где нет инкремента, данные хранятся в памяти, а считаются в регистрах). Примерно так будет в псевдокоде:
    int preinc(int i) {
      mov r1, [i];
      add r1, 1;
      mov [i], r1;
      return r1;
    }
    int postinc(int i) {
      mov r1, [i];
      mov r2, r1;
      add r2, 1;
      mov [i], r2;
      return r1;
    }

    Видно, что у постфиксного варианта на одну операцию больше, чем у префиксного. А так же постфиксный использует 2 регистра, тогда как префиксный 1.
    Логика работы префиксного проще и понятней. Так что используйте по умолчанию всегда префиксный. И только тогда когда действительно необходимо постфиксный.

    А теперь представьте, что операция производится не надо встроенным типом, а надо классом. В этом случае дополнительные затраты могут быть гораздо существенней.
    Ответ написан
    2 комментария