Ответы пользователя по тегу C++
  • Указатели в C++: что такое "x{"?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело в том, что для char* работает особый механизм вывода в поток. Этот указатель воспринимается не как адрес, а как строка Си. Первым символом строки будет, разумеется, R. А дальше — идёт по памяти и выводит все байты подряд, пока не обнаружит 0.

    Поскольку после char (1 байт) идёт char* (8 байтов), нам придётся создать семь байтов выравнивания (судя по длине указателя, мы на x64). В этих семи байтах и обнаружились фигурная скобка, ноль и непонятно что.

    Поставьте вместо char int — будет всё, как вы думали. Указатель int* выводится без всяких интерпретаций.
    Ответ написан
    2 комментария
  • Как правильно создать локальную копию std::wstring?

    @Mercury13
    Программист на «си с крестами» и не только
    void doSomething(std::wstring* s)
    {
       std::wstring temp = *s;
    }
    Ответ написан
    1 комментарий
  • Где и в каких случаях правильно использовать extern?

    @Mercury13
    Программист на «си с крестами» и не только
    Назначение extern единственное. Мы говорим, что этой переменной нет в данной единице компиляции, но не надо переживать, она есть в другой и компоновщик её подкомпонует.

    По факту является extern’ом static-поле класса. Это решение принято Строуструпом по простой причине: определение класса может промелькнуть несколько раз в разных единицах компиляции, а определение переменной должно быть одно на программу.

    Если ваш код не работает без extern — это значит, что где-то нашлась глобальная переменная по имени client, и для корректной работы вебмастера потребовалось обращаться к этому нашему клиенту. По факту — очень навороченный способ создать static-поле.

    Таким образом, у вас три варианта.

    1. Если Ethernet-клиент один на всех вебмастеров, вам нужно static-поле.
    // HEADER
    class WebMaster {
    public:
        WebMaster();
        bool connect_open();
    private:
        static EthernetClient client;
    }
    
    // CPP
    EthernetClient WebMaster::client;


    Впрочем, этот вариант крайне маловероятен.

    2. Скорее всего, у вас один вебмастер — один клиент и, вероятно, вам нужно обычное нестатическое поле.
    class WebMaster {
    public:
        WebMaster();
        bool connect_open();
    private:
        EthernetClient client;
    }


    3. Если у нас приходится привязывать мастеров к клиентам, приходится использовать указатели и ссылки. В простейшем виде…
    // HEADER
    class WebMaster {
    public:
        WebMaster(EthernetClient& aClient);
        bool connect_open();
    private:
        EthernetClient& client;
    }
    
    // CPP
    WebMaster::WebMaster(EthernetClient& aClient) : client(aClient) {}
    
    ...
    EthernetClient client;
    WebMaster webmaster(client);
    Ответ написан
    Комментировать
  • Почему не компилируется код при подключении vector?

    @Mercury13
    Программист на «си с крестами» и не только
    Вероятнее всего, где-то в предыдущем хедере — в том, что находится перед нашим <vector> — что-то не закрыто (пространство имён, функция и т.д.)

    UPD2. Получилось повторить ошибку таким кодом.
    void x() {
    #include <vector>
    };

    Если вместо функции x() взять класс или пространство имён, ошибка будет другая.
    Так что 90%, что вы не сбалансировали скобки в функции.
    Ответ написан
    2 комментария
  • Почему программисты не любят возврат константных ссылок в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Я думаю, причина единственная — не надо смотреть на время жизни объекта.
    Если же нужно сэкономить, в возвращаемый результат встраивают умный указатель. Так работают, например, QString и QDatabase.

    А вот в каких-нибудь низкоуровневых векторах — вполне себе константные ссылки.
    const T &QVector::at(int i) const
    Ответ написан
    Комментировать
  • Запуск готового файла .bat в QT Quick?

    @Mercury13
    Программист на «си с крестами» и не только
    Это системно-зависимая задача, и в Qt такое только частично. Под Windows она выполняется так.
    1. Получить путь к COMMAND.COM, считав переменную окружения COMSPEC. Для этого есть класс QProcessEnvorinment.
    2. Запустить программу (CreateProcess или ShellExecute) с командной строкой "/c filename parameters". В Qt есть объект QProcess, его работоспособность я не проверял.
    3. Если ещё и нужно куда-то передать результат выполнения — разбирайтесь с перенаправлением ввода-вывода функции CreateProcess. В QProcess, вероятно, перенаправление ввода-вывода тоже есть.
    Ответ написан
    Комментировать
  • Как затереть ссылку возврата?

    @Mercury13
    Программист на «си с крестами» и не только
    Для чего это нужно? А для того, чтобы вы знали, как хакеры вас ломают. Простейший способ для этого — устроить переполнение буфера.
    void foo()
    {
      void* a[1];
      a[1] = (void*)&bar;
    }

    Может быть, придётся подменить не a[1], а a[2] или a[3].
    Если так поступить, bar-то будет вызван, но по выходу из него, скорее всего, программа упадёт. Как сделать, чтобы не упала — оставлю домашним заданием. Высший пилотаж — завести в main() пару переменных, а потом через std::cout показать: вот они, целые и невредимые (компилируйте без оптимизации, макс. оптимизация может их просто заменить константами). Но тут уже придётся знать соглашение вызова и читать дизассемблерный листинг: от этого зависит, как вернуть стек в подходящее состояние.

    UPD. Простите за моё незнание синтаксиса Си.
    Ответ написан
    5 комментариев
  • Как подключить libcurl к Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Подключать надо libcurldll.a в таком виде.
    -LC:\Qt\curl-7.49.0-win32-mingw\lib -lcurldll

    Вот кусок, взятый из реального проекта.
    win32|win64: LIBS += -lws2_32 -lshlwapi -lodbc32 -lpsapi -lcomdlg32 \
                         -L$$PWD/../../Common/cURL/lib/ -lcurldll -lole32 \
                         -loleaut32


    Кроме того, тебе не хватает OpenSSL — найди libeay32.dll и ssleay32.dll, лучше скомпилированные старой версией MSVC и не требующие новых runtime’ов, которые есть не везде. Ах да, есть версии libcurl, которые скомпилированы без SSL — им этого, разумеется, не нужно.

    Подожди, сейчас посмотрю, что будет, если вкомпилировать в программу библиотеку cURL статически, без DLL.

    UPD. Попробовал. Почти работает, но надо разобраться, как подключить winsock и OpenSSL — раньше-то ими занимался тот, кто компилирует DLL, а сейчас это будет моя забота.
    Ответ написан
  • Как поместить "нетривиальный" объект в стуктуру?

    @Mercury13
    Программист на «си с крестами» и не только
    Одно из полей (в данном случае data в реализации item<Edge>) не имеет конструктора по умолчанию. Есть три пути.

    РАЗ. Придумать, как сделать, чтобы конструктор всё-таки был.
    class Edge : public EdgeBase
    {
    public:
      Edge (Point* firstPoint, Point* secondPoint) { init(firstPoint, secondPoint); }
      Edge () { init(NULL, NULL); }
      void init (Point* firstPoint, Point* secondPoint)
      {
        this->firstPoint = firstPoint;
        this->secondPoint = secondPoint;
      }
    private:
      Point* firstPoint;
      Point* secondPoint;
    };


    ДВА. Если объект копируется/переносится, можно воспользоваться такой штукой. С вашего позволения, упрощу задачу и вместо Edge заведу другой класс — ImmutableInt. Правда, этот код — попытка совместить ежа с ужом (непонятно, какую концепцию должен поддерживать Payload), но, тем не менее, работает.
    #include <iostream>
    
    class ImmutableInt
    {
    public:
        explicit ImmutableInt(int x) : fData(x) {}
        int data() const { return fData; }
    private:
        int fData;
    };
    
    template <class Payload>
    class ListItem
    {
    public:
        Payload payload;
        ListItem* next;
    
        ListItem() : next(NULL) {}
        ListItem(const Payload& x) : payload(x), next(NULL) {}
    };
    
    // Так писать нельзя — эта конструкция расшаблонивает все функции,
    // а конструктора по умолчанию как не было, так и нет!
    //template class ListItem<ImmutableInt>;
    
    int main()
    {
        ListItem<ImmutableInt> li(ImmutableInt(42));
        std::cout << li.payload.data() << std::endl;
        return 0;
    }


    ТРИ. Воспользоваться переменными шаблонами (variadic templates) C++11.
    #include <iostream>
    
    class ImmutableInt
    {
    public:
        explicit ImmutableInt(int x) : fData(x) {}
        int data() const { return fData; }
    private:
        int fData;
    };
    
    template <class Payload>
    class ListItem
    {
    public:
        Payload payload;
        ListItem* next = nullptr;
    
        template<class... Args>ListItem(Args... args) : payload(args...) {}
    };
    
    int main()
    {
        ListItem<ImmutableInt> li(42);
        std::cout << li.payload.data() << std::endl;
        return 0;
    }


    P.S. Хотя ImmutableInt — семантически тот же int и теоретически explicit не надо, всё-таки отметил — просто чтобы показать, что во втором случае мы передаём параметром ImmutableInt<42>, а в третьем — 42.

    P.P.S. Я упомянул слово «концепция». Это набор требований к типу. Что-то типа интерфейса — но, во-первых, никак не связано с ООП и его динамическим полиморфизмом, и, во-вторых, не столь жёсткое: как ты интерфейсом из Java наладишь концепцию «есть конструктор копирования» или «может делить себя на число и что-то выходит»? Синтаксическая поддержка концепций откладывается на C++17, но уже в C++03 было несколько концепций: InputIterator, DefaultConstructible, CopyAssignable и другие. А пока… концепция не поддерживается — ошибка компиляции где-то в страшенном стандартном хедере.

    P.P.P.S. Написав код
    template<typename type_t>
    struct item
    {
      item* next;
      type_t data;
    };

    вы автоматически потребовали от type_t концепцию DefaultConstructible (есть конструктор по умолчанию)
    Ответ написан
    1 комментарий
  • Как программно скачать несколько файлов с сайта?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Заполучить принцип, по которому строятся ссылки. Возможно, для этого придётся разбирать код самого сайта.
    2. Использовать любую библиотеку HTTP: Indy (Delphi), cURL (DLL с большим количеством привязок) или что-нибудь другое. С другими я, к сожалению, не работал. Ну или просто запускать подходящий EXE-загрузчик (wget, curl…).
    3. Обойти анти-DDoS’овские меры. Многие сети раздачи контента проверяют, похож ли клиент на легитимный браузер — наш бот должен все эти меры обойти.

    Знаю, что слабость последних версий Indy — ориентация на .NET и вытекающие оттуда ограничения; также Indy «слишком вумный» и сложные REST-службы не работают, так как строишь тело, вычисляешь имитовставку — а служба говорит, что они друг другу не соответствуют; видимо, Indy что-то подстроил. Кстати, когда я понял, что запросы без тела работают, а с телом — ни в какую, первым тестом стал curl.exe, и только потом подключил libcurl через собственную Delphi-привязку.

    Слабость cURL — тонкости протоколов (скажем, заголовки и кодировки) остаются за прикладными программистом; ориентирован на FILE* и на всех языках, кроме Си, запись в файл слегка затруднена; ориентирован на vararg и если работать без типобезопасной обёртки, надо быть предельно осторожным.
    Ответ написан
    Комментировать
  • Как изменять значения переменных другого класса в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Не буду говорить о качестве кода, const-корректности и прочей бяке. Конкретная ваша ошибка
    int& operator [](int i) // именно ссылка!

    У вас возвращается значение — временный объект, которому, разумеется, невозможно присвоить что бы то ни было.
    Ответ написан
  • Как удалить элемент из вектора, а затем добавить несколько новых?

    @Mercury13
    Программист на «си с крестами» и не только
    У вас могут быть две проблемы.
    1. Неверно написана операция «присвоить» или «переместить».
    2. Забыл, что в std::vector при операции «добавить» или «удалить» возможно физическое перемещение объекта и ссылки на него больше недействительны.

    Ну и IsEnded лучше писать вот так.
    bool IsEnded(const Query &aVar) { return (aVar.id == NO_ID); }
    Ответ написан
    2 комментария
  • Что будет содержать абстрактный класс?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариант один вы предложили. Всё пишу на C++03, без шаблонов. C++11 и шаблоны, разумеется, дадут больше вариантов.
    class Object {
    public:
        virtual ~Object() {}
    };
    
    class List {    // interface
    protected:
        virtual Object& getAt(size_t i) = 0;
    public:
        virtual size_t size() const = 0;
        inline Object& at(size_t i) { return getAt(i); }
        inline const Object& at(size_t i) const
            { return const_cast<List*>(this)->getAt(i); }
        virtual ~List() {}
    };

    Вариант 2. С ним пользователю не так просто, но если к нему ещё добавить лямбда-функции C++11 — вообще бомба будет!
    class ListCallback {    // interface
    public:
        virtual void act(size_t index, Object& object) = 0;
        virtual ~ListCallback() {}
    };
    
    class ListConstCallback {   // interface
    public:
        virtual void act(size_t index, const Object& object) = 0;
        virtual ~ListConstCallback() {}
    };
    
    class List2 {   // interface
    public:
        virtual size_t size() const = 0;
        virtual void enumerate(ListCallback& body) = 0;
        virtual void enumerate(ListConstCallback& body) const = 0;
    };

    Например, для динамического массива, у которого быстрый доступ по номеру, будет такое тело
    void DynArray::enumerate(ListConstCallback& body) const {
       size_t sz = size();
       for (size_t i = 0; i < sz; ++i)
           body(i, operator[](i));
    }

    Разумеется, если вы нагрузкой сделаете не абстрактный Object, а что-то окончательное, dynamic_cast не нужен будет.

    Вариант 3 принят в Java. Один недостаток — мого кода писать для const-корректности, так что с вашего позволения опущу.
    class VirtualListIterator { // interface
    public:
        virtual bool next() = 0;
        virtual Object& value() = 0;
        virtual ~VirtualListIterator() {}
    };
    
    class ListIterator {   // Назван так для красоты, по сути это умный указатель
    private:
        VirtualListIterator* ptr;
        // Запретим копирование и op=, но при желании можно реализовать и их
        ListIterator(ListIterator&) {}
        void operator=(const ListIterator&) {}
    public:
        ListIterator() : ptr(NULL) {}
        ListIterator(VirtualListIterator* value) : ptr(value) {}
        ~ListIterator() { delete ptr; }
        bool next() { return ptr->next(); }
        Object* operator->() const { return &ptr->value(); }
        Object& operator*() const { return ptr->value(); }
    };
    
    class List3 {   // interface
    public:
        virtual size_t size() const = 0;
        virtual VirtualListIterator* enumerate() = 0;
    };
    
    class Number : public Object {
    public:
        int value;
    };
    
    // И пользоваться этим так...
    void doSmth(List3& aList) {
        ListIterator it(aList.enumerate());
        while (it.next()) {
            std::cout << dynamic_cast<Number&>(*it).value << std::endl;
        }
    }


    Во всех трёх вариантах не забывайте: если нагрузка — не что-то окончательное, а абстрактный класс, элементы придётся хранить по указателю и вручную уничтожать.

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

    @Mercury13
    Программист на «си с крестами» и не только
    Операция присваивания или перемещения есть? Пускай даже созданная автоматически? Если есть — вот, смотрите.
    #include <iostream>
    #include <vector>
    
    class Test {
      int k;
    public:
      Test(int _i) {k = _i; }
    
      void put_k(int i) {k = i; }
      int get_k() {return k; }
    };
    
    
    struct TestWrapper {
        Test payload;
        TestWrapper() : payload(0) {}
        TestWrapper(int i) : payload(i) {}
        TestWrapper(const Test& i) : payload(i) {}
    };
    
    int main()
    {
        Test test(10);
        std::vector<TestWrapper> v;
        v.push_back(test);
        std::cout << v[0].payload.get_k() << std::endl;
        return 0;
    }


    Если нет — тогда динамический массив так просто работать не может (фишка динамического массива — заводить новый массив и копировать информацию из старого). Только использованием умных указателей.
    #include <iostream>
    #include <vector>
    #include <memory>
    
    
    class Test {
      int k;
    public:
      Test(int _i) {k = _i; }
      Test& operator=(const Test&) = delete;
      Test& operator=(Test&&) = delete;
    
      void put_k(int i) {k = i; }
      int get_k() {return k; }
    };
    
    
    int main()
    {
        std::vector<std::unique_ptr<Test>> v;
        v.push_back(std::unique_ptr<Test>(new Test(10)));
        std::cout << v[0]->get_k() << std::endl;
        return 0;
    }
    Ответ написан
  • Передача узла дерева?

    @Mercury13
    Программист на «си с крестами» и не только
    По сути. Вы забыли порядок исполнения операций.
    (*root)->next.push_back(node);

    Чем ещё можно улучшить код…
    Зачем вам указатель на указатель? Как массив указателей? Как «либо ссылка на указатель, либо ничего»? По видимому, ни то, ни другое, указатель, по сути передаётся по значению — так что стоило бы функцию переделать как…
    bool Syntax::On_BG(Node * root)
    или даже
    bool Syntax::On_BG(Node & root)

    PS. И да, указатель передаётся по значению, но то, на что он указывает, не исчезнет с выходом из функции.
    Ответ написан
  • Qt, Время собирать "камни" или как получить Release?

    @Mercury13
    Программист на «си с крестами» и не только
    «can't find -lQSerialPort» — это значит, не в инклудах дело, а в .lib или в .a (зависит от компилятора). Ищи, как указать путь к этому файлу. И почему в отладке работало? — там что, этот путь указан?
    Ответ написан
    4 комментария
  • Как лечить char warning overflow при считывании с файла?

    @Mercury13
    Программист на «си с крестами» и не только
    fin.getline(pRun->sBooks.chBook, 99, static_cast<char>('»'));


    Всё у вас правильно. А в Си char почему-то (обычно) знаковый.
    Ответ написан
  • Приведение обьекта производного класса к базовому?

    @Mercury13
    Программист на «си с крестами» и не только
    Через указатели и ссылки — останется.
    По значению (как у тебя сейчас в векторе) — преобразуется в базовый.

    Главная проблема работы с указателями и ссылками — где хранить объекты и как их уничтожать. Хранят обычно в «куче», а для уничтожения используют умные указатели или что-то самописное под задачу. Вот, например, решение на умных указателях C++11:
    #include <iostream>
    #include <memory>
    #include <vector>
    
    class Base{
    public:
        // Нужен виртуальный деструктор, ведь мы будем уничтожать детей
        // через родительский ук-ль. Да и dynamic_cast требует RTTI,
        // а значит, хоть одного виртуального.
        virtual ~Base() = default;
    };
    
    class Exp: public Base
    {
    int i=0;
    public:
           int Get() const {  return i; }
           void Set(const int &num) { i=num; }
    };
    
    std::vector<std::shared_ptr<Base>> MyStack;
    Base &GetRef() { return **MyStack.begin();  }
    
    int main() {
        std::shared_ptr<Exp> a = std::make_shared<Exp>();
        a->Set(4);
        MyStack.push_back(a);
        int res=dynamic_cast<Exp&>(GetRef()).Get(); // Теперь работает
        std::cout << res << std::endl;;
    }
    Ответ написан
    Комментировать
  • Что такое normaliz.dll?

    @Mercury13
    Программист на «си с крестами» и не только
    Нормализация Юникода.
    Обычно находится в Windows\System32 (Windows\SysWOW64).
    Официальный сайт не держит библиотек cURL, он только даёт ссылки на чужие сборки. cURL (или OpenSSL) использует VC2008; вы явно скачали версию НЕ для XP. Ничего, VS2008 Redistributable можно скачать тут.
    https://www.microsoft.com/en-us/download/details.a...

    Я специально искал и нашёл сборку cURL/OpenSSL, которая не требует ничего необычного. Мы программисты, ставим кучу софта — а у одного бета-тестера не прокатило, т.к. на его рабочем ноутбуке не было VS2013, приблудил с OpenSSL.
    Ответ написан
    Комментировать
  • Как заставить сработать исключение std::bad_alloc?

    @Mercury13
    Программист на «си с крестами» и не только
    #include <iostream>
    #include <conio.h>
    
    int main()
    {
      setlocale(LC_ALL, "Russian");
      const size_t SIZE = 3000000000ul;
      char* ptr = NULL;
      try
      {
        ptr = new char[SIZE];
        std::cout << "Память используется без сбоев.\n";
      }
      catch (std::bad_alloc&)
      {
        std::cout << "Исключение bad_alloc: невозможно разместить данные в памяти.\n";
      }
      delete[] ptr;
      getch();
      return 0;
    }


    Столько кода — и столько ошибок! По пунктам.
    1. Ответ на ваш вопрос. Сделать константу побольше. Кстати, эта константа — size_t. В 64-битном коде надо ещё больше.
    2. Не проработано поведение delete[], если случится ошибка. Покатит инициализация NULL.
    3. Если случится ошибка, будут выведены оба сообщения.
    4. getch — функция из платформозависимого заголовка conio.h. Только DOS/Windows.
    5. Обработку аварий обычно делают по ссылке.
    6. Для первого параметра setlocale надо указывать ненулевую маску, на какие части ставить локаль. LC_ALL — везде. Что писать вторым параметром, зависит от библиотеки времени выполнения.
    Ответ написан
    7 комментариев