Ответы пользователя по тегу C++
  • Зачем нужны шаблоны, если есть макросы?

    @nirvimel
    1. Статическая типизация (если для вас это не сильный аргумент, то вам, наверное, больше подойдет что-то вроде Python).
    2. Более адекватные сообщения об ошибках компиляции при круто накрученной логике на макросах/шаблонах.
    3. https://msdn.microsoft.com/en-us/library/z3f89ch8(...
    Ответ написан
    Комментировать
  • Алгоритм многопоточности?

    @nirvimel
    Не надо создавать отдельный поток для каждого файла. Создайте два пула потоков.

    Пул №1 (вычислительный): количество потоков равно количеству ядер CPU. Во входную очередь сыплются блоки данных, для которых потоки пула рассчитывают хеши.

    Пул №2 (синхронное чтение с диска): количество потоков равно количеству ядер, помноженному на некоторую константу (в исходниках разных библиотек я видел значения от 2 до 10). Во входную очередь сыплются имена файлов, которые потоки пула открывают, читают и засылают прочитанные блоки во входную очередь пула №1.
    Примечание: расход памяти регулируется ограничением максимальной длинны входной очереди пула № 1. Практически получается, что пул №1 ограничивает нагрузку на пул №2, который в норме недонагружен.

    Отдельный поток, который совершает обход дерева каталогов и засылает найденные имена файлов во входную очередь пула №2. Длину этой очереди, тоже можно ограничить, но не так жестко (я бы задал размер в несколько сотен).

    P.S.: Все очереди с ограничением длины должны быть, конечно же, с блокировками (не lock-free), так как через них происходит регулировка нагрузки (иначе все потоки нагрузятся на 100%).
    Размер блоков данных, поступающих на вход пула №1 не надо делать слишком маленьким (я бы задал 64 килобайта, например).
    Ответ написан
    Комментировать
  • Какую книгу по С++ прочесть для новичка?

    @nirvimel
    Здесь вся основная литература по C++ структурирована по уровням.
    Ответ написан
  • Try-catch-throw. Как понять эту схему?

    @nirvimel
    Вы называете одним словом "ошибка" несколько совершенно различных вещей, не связанных между собой:
    1. Синтаксическая ошибка в исходном коде. "где в тип string вводится int и сообщается об ошибке" - это невозможно в принципе, так как ваш исходный код, в котором нарушено соответствие типов, не является валидной программой (все равно что оставить незакрытую скобку), компилятор не сможет скомпилировать из него никакой бинарный исполнимый файл просто потому, что видит бессмыслицу в таком исходнике.
    2. Исключительная ситуация (exception) во время выполнения. Она всегда предусмотрена кодером (этим она и отличается). Например я пишу функцию, которая должна делить одно число на другое, я предполагаю, что кто-то (типа меня же) может использовать эту функцию неправильно и передать ноль в качестве делителя. Я хочу, чтобы такому пользователю прилетел (по голове) exception, красноречиво сообщающий о том, что так делать не стоит. Для этого я пишу
      if (denominator == 0) { throw std::invalid_argument( "НЕ НАДО ТАК!" ); }
      . Теперь, если мне нужно выполнить какой-то кусок кода, в котором есть вызовы функций, из которых могут вылетать исключения, и я хочу как-то локализовать эту проблему и обезопасить от этого остальную программу, то я пишу
      try { divide(x, 0); } catch (const std::invalid_argument& e) { /* Я все понял, я так больше не буду. */ }
      .
    3. Undefined behavior - это результат не предусмотренной никем ситуации во время выполнения. Например, я заб(ы/и)л на то, что кто-то может передать ноль в мою функцию в качестве делителя и пишу int divide(int a, int b) { return a / b; }. И однажды это происходит, кто-то (да я же сам) передает туда ноль и... Что должно произойти в этой ситуации? Я не знаю, CPU не знает, компилятор об этом не позаботился, ОС тоже не знает, но на всякий случай она прихлопнет весь процесс целиком и (возможно) напишет в консоль что-то типа segmentation fault.
      А что, если я буду вызывать такую подозрительную функцию из блока try-catch? - Да ничего это не меняет. try-catch ловит только преднамеренно брошенные исключения в ситуации, когда возможность возникновения ошибки была предусмотрена кодером. try-catch ничем не может помочь против undefined behavior потому, что предусматривать возможные ошибки во время выполнения - это задача кодера, а не компилятора, который занимается только контролем соответствия типов и формальной корректности программы.


    Если вам не по душе концепция undefined behavior, то переходите на Java или .NET, там компиляторы сами добавляют все необходимые (и обходимые) проверки ценой снижения быстродействия вашей программы.
    Ответ написан
    3 комментария
  • Как экранировать кавычки в sqlite3 запросе на языке с++?

    @nirvimel
    Лучше всего это делать НИКАК.
    А параметры передавать через связываемые переменные.

    Тут по-русски общая теория вопроса без относительно SQLite.
    Ответ написан
    2 комментария
  • Есть ли смысл учитывать аппаратное количество потоков в игровом движке?

    @nirvimel
    Пул потоков по умолчанию содержит число потоков, равное количеству ядер аппаратных потоков. У этого пула есть входная очередь (lock-free), куда сабмитятся поступающие таски. Когда CPU недонагружен очередь пустая. Когда все потоки заняты, очередь растет.

    Это рецепт максимальной производительности, за исключением того случая, когда по условиям задачи критично, чтобы большое количество тасков выполнялось реально параллельно (например сами задачи продолжительные, а разбивать их на подзадачи нет возможности или желания), тогда все задачи должны быть разложены по отдельным потокам ОС.

    Кстати, очередь задач на пуле потоков - это именно то, как многозадачность реализуется внутри ОС. Только тут сами потоки ОС являются тасками, которые ставятся в очередь. Разница в производительности объясняется тем, что переключение тасков в юзерспейсе легче (следовательно быстрей), чем переключение потоков ОС.
    Ответ написан
    2 комментария
  • Какова реализация или советы по реализации чтения и поиск информации с сайта на c++ (Парсер)?

    @nirvimel
    1. Закачка страниц из сети при помощи libcurl.
    2. Разбор страниц в DOM при помощи libxml2 (или libxml++).
    3. Выборка интересующих элементов (ссылки, картинки, и.т.д.) при помощи XPath запросов к DOM.
    4. Многопоточность: заброс новых ссылок в общую очередь + пул потоков, выбирающих себе задания из этой очереди и отрабатывающих по пунктам 1, 2, 3.

    так как некоторые ссылки могут быть скриптами или css

    С этим нет никакой проблемы. XPath //a выбирет только реальные ссылки на страницы, по которым возможно перейти.
    Ответ написан
    1 комментарий
  • Как обратиться по индексу к списку C++?

    @nirvimel
    bubble sort on linked list
    На то он и Пузырек, что не нужен там доступ по индексу.
    Ответ написан
    Комментировать
  • Как решить проблему «Запуск невозможен. Отсутствует MSVCP140.dll»?

    @nirvimel
    Нужно установить Visual C++ Redistributable for Visual Studio 2015.
    Ответ написан
    Комментировать
  • Как прочитать указатель из памяти чужого процесса?

    @nirvimel
    ArtMoney недостаточно для написания полноценного runtime-патча. Потребуется полноценный отладчик, чтение и понимание фрагментов кода, которые ответственны за чтение/запись этого значения.
    Могу предсказать проблему, с которой вы столкнетесь, пытаясь выявить (якобы существующую) цепочку указателей - при каждом новом запуске это значение (и все указатели на него) будет появляться по новому адресу.
    spoiler
    Ибо не все так просто.
    Ответ написан
    3 комментария
  • Что значит выражение "выстрелить себе в ногу?" (в виде кода)?

    @nirvimel
    *((int *) 0) = 1;
    Ни в одном другом языке это не осуществляется так просто.
    Ответ написан
    3 комментария
  • Как заставить текущий объект перезаписать самого себя?

    @nirvimel
    В режиме телепатии догадываюсь, что вы хотите реализовать. Видимо, речь идет о совершенно стандартном механизме порождения объекта соединения из объекта БД.
    Чтобы понять как строятся подобные велосипеды загляните в код любой ORM или вообще любой ООП-обертки над драйвером БД. Вы увидите в большинстве случаев следующую картину:
    1. Конфигурация БД представляет собой фабрику (да, да, те самые паттерны, которые неофитам НИНУЖНЫ).
    2. Метод connect возвращает объект соединение.
    3. Объект соединение (кроме методов по выполнению запросов) имеет метод close, который закрывает соединение (попытка выполнения запроса на закрытом соединении будет выдавать ошибку).
    4. Соединение (как объект) живет один раз и не может быть переоткрыто после закрытия. Но из фабрики БД всегда можно открыть новое соединение.

    Почему так:
    Главный принцип ООП: отдельному понятию - отдельный класс. БД (на стороне клиента) представляет собой только конфигурацию: адрес сервера, имя юзера, пароль, имя БД и прочие параметры. Соединение к БД - это отдельная сущность, через которую создаются транзакции и курсоры (отдельные сущности), через которые выполняются запросы. Результат выполнения запроса - отдельная сущность. Отдельная строка в выборке - отдельная сущность (если только не кортеж). И только отдельные поля в строке имеют примитивные типы данных.
    Ответ написан
    Комментировать
  • Что за конструкция?

    @nirvimel
    Ссылка на элемент массива line, который имеет тип Line.
    Ответ написан
    Комментировать
  • Как правильно параллельно обрабатывать файлы на c++?

    @nirvimel
    Завести vector<thread>.
    Сначала в цикле породить все потоки и сохранить в вектор.
    Потом другим циклом пройтись по всем и сделать join каждому.

    P.S.: В реальном коде с точки зрения производительности лучше проверять is_regular_file тоже внутри потока. И нет смысла в цикле читать из файла все строки ради значения последней (может лучше было бы - первой) строки. Что если попадется многогигабайтный файл?
    Ответ написан
    7 комментариев
  • Как получить низкоуровневое имя файла?

    @nirvimel
    Если файла не существует, то и не существует однозначно соответствующего ему внутреннего имени (FinalPath). В вашем примере как раз хорошо проиллюстрирован этот случай с COM1 и COM4, которым сопоставлены совершенно разные устройства. Какому устройству будет сопоставлено имя COM2 зависит от самих устройств (в том числе еще не подключенных на данный момент) и иногда даже от порядка их подключения.

    Это в общем случае... Но в частном случае может подойти такое решение: получить внутреннее имя (FinalPath) для каталога, в котором должен находиться несуществующий файл и через разделитель дописать к нему имя этого файла.
    Ответ написан
    Комментировать
  • Наиболее красивый и правильный способ передачи параметров сквозь другой класс?

    @nirvimel
    #include <iostream>
    
    class Cam;
    
    class OutputBuffer {
    public:
        OutputBuffer() { std::cout << "OutputBuffer " << this << " initialized\n"; }
    
        void receive(Cam &cam) { std::cout << "OutputBuffer " << this << " receiving data from camera " << &cam << "\n"; }
    };
    
    class Cam {
        static OutputBuffer buffer;
    public:
        Cam() { buffer.receive(*this); }
    };
    
    OutputBuffer Cam::buffer = OutputBuffer();
    
    int main() {
        Cam cam1, cam2;
    };


    OutputBuffer 0x6013d1 initialized
    OutputBuffer 0x6013d1 receiving data from camera 0x7fff7742970e
    OutputBuffer 0x6013d1 receiving data from camera 0x7fff7742970f
    Ответ написан
    4 комментария
  • Какие операции языка C++ могут быть потенциально небезопасны?

    @nirvimel
    Присваивание может быть перегружено, поэтому в общем случае может вызывать произвольный код, который может быть не безопасен, следовательно и сама операция не может считаться безопасной.

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

    В остальном приведенные рассуждения в целом верные, явных ошибок я не заметил.
    Ответ написан
  • Почему изменяются значения полей объекта структуры?

    @nirvimel
    Из getStudentData возвращается указатель на локальный объект student.
    Ответ написан
    3 комментария
  • Как подключить два разных файла с одинаковым именем?

    @nirvimel
    Не хотите, чтобы выглядело комично - не называйте файлы проекта именами стандартных заголовочных файлов.
    Но, не считая комичности, технически ни каких проблем с таким именованием не должно возникать.
    Ответ написан
    Комментировать
  • Может ли TCP соединение работать сразу с несколькими клиентами?

    @nirvimel
    TCP соединение - это сокет. Открытый сокет связывает конкретный порт на локальной машине с конкретным портом на конкретной удаленной машине (и никак иначе). Открытый сокет соединяет всегда две стороны. Не существует многосторонних сокетов. Но на одной машине может быть открыто сколько угодно сокетов.
    Ответ написан
    Комментировать