Ответы пользователя по тегу C++
  • Поможет ли вынос работы с крэшащейся библиотекой в отдельный поток от крэша всего приложения?

    @menkar3
    Вкратце - скорее всего нет. Кроссплатформенно - еще более сомнительно.
    Как именно крашится либа? Я так понял, это не вылетевшее C++ исключение, а что-то вроде коррапта памяти (хотя в самой либе может быть гадость вроде if(fail){exit(-1);}, с чем уже работать проблематично). В теории, можно для каждой платформы это обработать. Если сходу - как это можно реализовать для винды:
    На самом деле выносим работу с либой в отдельный поток. Когда она сделает что-то плохое (к примеру, попытается читать освобожденную память) будет выброшено SEH исключение, для которого мы можем зарегистрировать обработчик (using a vectored exception handler в msdn). В хендлере можно было бы проверить, что исключение выброшено именно из треда этой либы и если это действительно так - просто грохнуть этот тред. Но даже если сработает это крайне плохой метод - либа захватывает какие-то ресурсы и нет никакой гарантии, что она корректно их освободит при падении треда (да и что приложение вообще останется в согласованном состоянии - кто знает, почему она падает - может, там вообще половина памяти перед этим мусором перезаписывается). Короче, решение с потоком - это потенциально нестабильная работа всего приложения.
    Для изоляции памяти и использования ресурсов как раз и существуют процессы, как бы не хотелось от них уйти :)
    Так что решение с отдельным процессом, который будет изолировать все болячки либы и не давать им распространиться на все приложение таки самое безопасное.
    Ответ написан
    1 комментарий
  • Почему код не компилируется в Visual Studio 2019?

    @menkar3
    Потому что точка входа в приложение задается в студии настройках проекта, а вы, как я понимаю, создали дефолтный=)
    Первая ссылка в гугле: https://stackoverflow.com/questions/18067870/what-...
    Оф. документация - https://docs.microsoft.com/en-us/cpp/build/referen...
    Вкратце:
    5e4c3eb70af5d542955543.png
    Ответ написан
    5 комментариев
  • Как правильно настроить взаимодействие от переменной объявленной в классе?

    @menkar3
    Отвечу как сам понял вопрос, может быть вообще мимо.
    Основная проблема - сильная связность. У вас более низкоуровневый класс SocketServer зачем-то должен знать о существовании InstrumentInterface который им владеет.
    Я бы предложил передавать серверу в конструкторе "что-то", куда он сможет писать полученные данные. Простой пример - InstrumentalServer ждет, пока не поступят данные от сервера, и пишет их в девайс. Простой пример, который работает вечно - сервер просыпается раз в секунду, записывает данные и засыпает. При появление данных InstrumentalServer просыпается, пишет их в девайс, и засыпает, снова ожидая входящие данные. Классическая многопоточная задачка же. Удалил методы из интерфейса.
    struct MessageQueue
    {
        std::condition_variable cv;
        std::mutex messMtx;
        std::queue<std::string> serverMessages;
    };
    
    struct AbstractDevice
    {
        void processData(std::string message)
        {
            std::cout << message << std::endl;
        }
    };
    
    class SocketServer
    {
    public:
        SocketServer(MessageQueue& mess)
            : out(mess)
        {
            std::thread t(&SocketServer::processData, this);
            t.detach();
        }
    
        void processData()
        {
            for (;;)
            {
                try
                {
                    std::lock_guard<std::mutex> lock(out.messMtx);
                    // some output data
                    out.serverMessages.push("some string 1");
                    out.serverMessages.push("some string 2");
                    // completed this iteration
                    out.cv.notify_one();
                }
                catch (const std::exception& ex)
                {
                    std::cerr << ex.what() << std::endl;
                }
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
        }
    
    private:
        MessageQueue& out;
    };
    
    class InstrumentInterface {
    public:
        virtual ~InstrumentInterface() = default;
    };
    
    class InstrumentalServer : public InstrumentInterface
    {
    public:
        InstrumentalServer() = default;
    
        void addDevice(AbstractDevice* dev) { device = dev; };
    
        void waitForMessages()
        {
            for (;;)
            {
                std::unique_lock<std::mutex> lock(messages.messMtx);
                // sleep until messages received
                messages.cv.wait(lock, [this]() {return !messages.serverMessages.empty(); });
                while (!messages.serverMessages.empty())
                {
                    device->processData(messages.serverMessages.front());
                    messages.serverMessages.pop();
                }
            }
        }
    
    private:
        MessageQueue messages;
        std::unique_ptr<SocketServer> sockServer = std::make_unique<SocketServer>(messages);
        AbstractDevice* device;
    };
    
    int main()
    {
        AbstractDevice device;
        InstrumentalServer iServer;
        iServer.addDevice(&device);
        iServer.waitForMessages();
        return 0;
    }

    Можно было бы сделать отдельный мьютекс для девайса, конечно, чтобы надолго мьютекс сообщений не захватывать. Тогда под мьютексом сообщений создаем пустую очередь, свопаем ее с очередью сообщений, освобождаем мьютекс сообщений, захватываем мьютекс девайса, пишем в девайс.
    Я правильно понял вопрос?
    Ответ написан
  • Как обратиться к функции класса через итератор?

    @menkar3
    for (it = catalog.begin(); it != catalog.end(); ++it)
    {
            it->click();
    }

    передать в функцию указатель на list

    Вы полностью указали тип?
    void foo(list<File>* pList);
    Ответ написан
    6 комментариев
  • Где ошибка в коде и как ее исправить?

    @menkar3
    spoiler
    Все переписа...

    Замена1 (как сказали выше):
    CONTRY *a[100];
    на
    CONTRY* a = new CONTRY[100];

    Замена2 в main начиная отсюда:
    int winter = a[0]->gettemp_winter();
      int summer = a[0]->gettemp_summer();
    ...
    На
      int winter = a[0].gettemp_winter();
      int summer = a[0].gettemp_summer();
    ...и т.д.

    У вас теперь указатель на массив а не массив указателей, так что все -> меняем на .
    Ответ написан
    1 комментарий
  • Как сделать циклический сдвиг массива на 4 вправо?

    @menkar3
    std::rotate?
    #include <algorithm>
    ...
    int main()
    {
        const int n = 12;
        int a[n] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
        rotate(a, &a[n] - 4, &a[n]);
        for (auto n : a)
        {
            cout << n << " ";
        }
        return 0;
    }
    Ответ написан
    Комментировать
  • Page Guard Hooking на C++, как сделать?

    @menkar3
    Код не запускал, могу ошибаться.
    1. Скорее всего, у вас произошло что-то вроде:
    1. Вся страница памяти защищена PageGuard
    2. Летит исключение STATUS_GUARD_PAGE_VIOLATION не с адреса 0x116F3
    3. VectoredExceptionHandler возвращает EXCEPTION_CONTINUE_SEARCH

    2. Саму copyAddress нужно сделать исполняемой через VirtualProtect (а лучше сразу выделить через VirtualAlloc с PAGE_EXECUTE_READWRITE)
    3. Вы копируете страницу не с начала, а с инструкции push 1388.
    Получаем что-то вроде (1:54 на видео):
    ="MEMORY PAGE"=
    ... push 1388
    ... call ...
    ... cmp ...
    ... call ...
    EB C7 jmp ...
    ...
    ===============
    Т.е. все будет хорошо ровно до момента, когда управление доходит до джампа (переход на следующую итерацию цикла while). Смотрим на двухбайтные джампы и ожидаемо видим, что это скачок назад - т.е. куда-то до push 1388, с которой вы начали копировать. Джампы относительные, так что управление было бы передано куда-то в мусорную память.
    Ответ написан
    Комментировать
  • Как изменить значение у всех владельцев shared_ptr?

    @menkar3
    В принципе, для случая "shared_ptr, который может стать невалидным" и существует std::weak_ptr
    Примитивное решение заключается в том, чтобы хранить std::shared_ptr только в кеше (который отвечает за владение объектом), а клиентам выдавать std::weak_ptr на него.
    class Base
    {
    public:
        virtual ~Base() = default;
    };
    
    class Derived : public Base {};
    
    int main()
    {
        std::map<std::string, std::shared_ptr<Base>> cache;
        cache.insert(std::make_pair<std::string, std::shared_ptr<Base>>
            ("key", std::make_shared<Derived>()));
        std::weak_ptr<Base> ptr(cache["key"]);
        assert(cache["key"].get() == ptr.lock().get());
        // invalidation
        cache["key"].reset(new Derived);
        assert(ptr.expired());
        // check on every access
        if (ptr.expired())
            ptr = cache["key"];
        assert(cache["key"].get() == ptr.lock().get());
        return 0;
    }

    Проблемы:
    1. Маленькая проблема - перед каждым обращением к объекту нужно проверять expired() (ну, или проверять полученный после lock() shared_ptr на предмет пустоты)
    2. Большая проблема - многопоточность. Как между вызовами expired() и lock() так и при работе с shared_ptr, возвращенным lock() в любой момент может произойти инвалидация кеша. Простого решения сходу не вижу, выбор способа синхронизации остается за вами
    Ответ написан
    Комментировать
  • Изучаю паттерны, возник вопрос по поводу паттерна Singleton, он должен выглядеть примерно так?

    @menkar3
    Я бы рекомендовал версию от Майерса. Как минимум из-за thread-safe initialization.
    Ответ написан
    Комментировать