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

    @Mercury13
    Программист на «си с крестами» и не только
    Так сравнивать безопасно. Единственный вопрос — может ли появиться ноль во время вычислений и не сломает ли это логику программы?
    Лучше, конечно, для этого использовать не 0.0, а 0.0f.
    Ответ написан
    2 комментария
  • В чем ошибка в операторе присвоения?

    @Mercury13
    Программист на «си с крестами» и не только
    Здесь нужны две операции: «присвоить» (возможно, автоматически сгенерированная) и конструктор копирования.
    class MP3_Format {
       MP3_Format(const char* c_string);
       MP3_Format& operator=(const MP3_Format&);   // велика вероятность, что компилятор её сгенерирует автоматически
    };


    Если пишете на C++11 — вместо операции «присвоить» нужна операция «присвоить из временного объекта». Опять-таки, годится автоматически сгенерированная.

    Семантика языка C++ в этой строчке такова. Мы создаём временный объект MP3_Format("Summertime"), а затем переносим его в наш mp3a. Скорее всего, оптимизатор уберёт этот перенос и инициализирует mp3a на месте, но такова уж семантика…
    Ответ написан
    1 комментарий
  • Почему появляется ошибка компилятора '?

    @Mercury13
    Программист на «си с крестами» и не только
    Ошибся тут не компилятор, а линкер. Этот вопрос идёт со времён Си и происходит из технологии компиляции: несколько единиц компиляции компилируются независимо, а потом собираются воедино компоновщиком (линкером).

    Статический член класса — это глобальная переменная, и если объявлять её в каждой единице компиляции, то какую потом линкеру брать? Вот мы и пришли к выводу: static int counter; в хедере — это тот же extern. Другими словами, мы не объявляем переменную, а говорим: не беспокойся, компилятор, в какой-то единице компиляции она будет.

    И решается этот вопрос так же, как для любого extern’а: в одной единице компиляции (CPP) объявляем
    int Skript::counter;
    Можно также статически инициализировать этот счётчик:
    int Skript::counter = 0;

    Ах да. А технология эта с единицами компиляции откуда? Из ассемблера. Если программа у нас почти на всю память в 16 килобайт, то ассемблерный текст намного, намного превышает память ПК. Вот и приходится ассемблировать по частям, а потом собирать куски полуготового машинного кода в полную программу. Наконец, чтобы язык заработал, КиР пришлось написать только компилятор Си, а линкер — имеющийся.
    Ответ написан
    Комментировать
  • Как указать путь создаваемого файла в c++?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Нам придётся работать с юникодными (wchar_t* / wstring) именами файлов. Использовать функции wfopen или CreateFile.
    2. Чтобы заполучить путь к рабочему столу, надо исполнить вот что.
    std::wstring desktopPath;
    wchar_t tmp[MAX_PATH + 1];
    if (SHGetSpecialFolderPathW(HWND_DESKTOP, tmp, CSIDL_DESKTOPDIRECTORY, FALSE))
        desktopPath = tmp;

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

    @Mercury13
    Программист на «си с крестами» и не только
    Вводить по символу, проверяя функцией isdigit, цифра это или нет.
    Ответ написан
    Комментировать
  • Как создать обьект с std::initializer_list?

    @Mercury13
    Программист на «си с крестами» и не только
    Это нельзя, initializer_list — это тонкая прослойка, позволяющая инициализировать вектор из линейного массива. Ни на что большее она не нужна.

    У вас есть какая-то странность — SearchVektor<unsigned int> мы инициализируем из вектора vector<int>. Это вообще ни в какие ворота не пишется. Для данного случая вам нужно…

    1. vector<int> liste превратить в vector<unsigned int>.
    2. Написать конструктор, работающий из временного вектора: SearchVektor(std::vector<T> && t ). Такой конструктор будет очень быстрым, ибо дерёт всю информацию из t, оставляя в нём пустоту.
    3. Объявить liste временным —
    return  SearchVektor< unsigned  int> (std::move(liste));
    Ответ написан
    4 комментария
  • Переопределить operator() для получения доступа к члену класса?

    @Mercury13
    Программист на «си с крестами» и не только
    class Window{
    public:
      Graphics& operator * () const { return *g; }
      Graphics* operator -> () const { return g; }
    private:
      Graphics *g;
    }
    
    ...
    
    window->Clear(Color::White);
    Ответ написан
    2 комментария
  • Как написать функцию которая может не вернуть значение?

    @Mercury13
    Программист на «си с крестами» и не только
    Object* find (const Object& o)
    {
        /* Поиск, если нашли */
       return link;
       /* Если не нашли? */
       return NULL; // Теперь можно
    }
    Ответ написан
    5 комментариев
  • Как использовать "гибкость" двумерного массива, перед одномерным?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, перед нами задача: сделать динамический массив «умных указателей единоличного владения». Умный указатель единоличного владения (std::unique_ptr из C++11) — это указатель, который самолично владеет выделенной памятью; при исчезновении указателя исчезает и память.

    Раз мы только учимся, мы не будем влезать в самописные шаблоны C++, готовые шаблоны STL (кроме algorithm и string) и новый, но уже реализованный во всех компиляторах стандарт C++11. Это довольно серьёзное ограничение; если его снять, можно серьёзно упростить себе жизнь. А для этого мы отделим структуру данных от жизненных объектов и реализуем объект StudentList. Пишу с листа, возможны ошибки.

    Да, и без C++11 умный указатель единоличного владения реализовать довольно тяжело — поэтому структуру данных будем делать «монолитно», без разделения на умный указатель и динамический массив.

    #include <algorithm>
    
    class StudentList
    {
    public:
      StudentList();
      ~StudentList();
      Student& add();   // добавить пустого студента и выдать ссылку на новенького
      size_t size() const { return fSize; }
      Student& operator[](size_t i) { return *fData[i]; }   // можно также наладить проверку диапазона — сделай это сам…
      const Student& operator[](size_t i) const { return *fData[i]; }
      void clear();
    private:
      typedef Student* PStudent;
      PStudent* fData;
      size_t fSize, fCapacity;   // реальное кол-во студентов и на сколько студентов у нас заведено памяти.
                            // Указатели [fSize..fCapacity) резервные, их значение не определено и высвобождать
                            // их не надо.
      enum { BLOCK_SIZE = 16; };
      StudentList(const StudentList&) {}   // копирование запрещаем, хочешь — реализуй сам и вынеси в public
      StudentList& operator=(const StudentList&) { return *this; }  // аналогично
    };
    
    StudentList::StudentList(); : fData(NULL), fSize(0), fCapacity(0) {}
    
    Student& StudentList::add()
    {
      // Убедиться, что массива хватает; если нет — расширить
      if (fSize >= fCapacity) {
        size_t newCapacity = fCapacity + BLOCK_SIZE;
        PStudent* newData = new PStudent[newCapacity];
        std::copy(fData, fData + fSize, newData);
        delete[] fData;
        fData = newData;
        fCapacity = newCapacity;
      }
      // Завести нового студента
      Student* r = new Student;
      fData[fSize++] = r;
      return *r;
    }
    
    void StudentList::clear()
    {
       for (size_t i = 0; i < fSize; ++i)
         delete fData[i];
       delete[] fData;
       fData = NULL;
       fSize = 0;
       fCapacity = 0;
    }
    
    StudentList::~StudentList()
    {
       clear();
    }


    Удаление и прочее сам наладишь?

    А группа будет пользоваться нашим списком.

    #include <string>
    
    class AcademyGroup
    {
    public:
       std::string name;
       StudentList students;  // при желании можно заинкапсулировать и его.
    };


    Это перед нами, правда, не двухмерный массив, как я уже сказал. Массив, хоть и Student**, но одномерный; каждый элемент массива — умный указатель единоличного владения. Если бы мы писали на STL C++11, это был бы std::vector<std::unique_ptr<Student>>.

    Кроме УУЕВ, существует также умный указатель совместного владения std::shared_ptr.

    Можно сделать второй вариант — массив из одномерных массивов. Если он заполнился — заводим ещё один массивчик. Пишется немного сложнее, особенно если не пользоваться STL. На STL — std::deque<Student>.
    Ответ написан
    6 комментариев
  • Как поймать в GDB исключение, вызванное из basic_string(const charT*)?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Нашёл.
    Подключить статический libc++ (-static-libstdc++), тогда всё будет.
    Ответ написан
    Комментировать
  • Почему this NULL в istream_iterator?

    @Mercury13
    Программист на «си с крестами» и не только
    Операторы перегружены правильно.

    А вот и нет. Ваша ошибка
    std::istream& operator>>(std::istream& s, Pnt& p)   // убрать const!

    Не обязательно, но можно.
    explicit Pnt(int s) {…} // добавить explicit!
    Что получается? Мы пытаемся считать в неизменную p.a. Прямое s >> p.a; не подходит — поле-то неизменное. И тут, как ни странно, находится цепочка: создать временный Pnt и снова вызвать саму себя!

    Добавить explicit: запрещаем вызывать этот конструктор неявно.
    Убрать const: расфиксировать p.a.

    Также у вас ошибка в перегрузке операции «присвоить».
    Pnt& operator=(const int a) {
           this->a = a;
           return *this; // ну забыл!
         }


    Насчёт explicit. Конструкторы с одним параметром вообще стоит делать explicit всегда, когда объект семантически отличен от параметра. Например, VeryLongInt(10) или Complex(10) — это та же десятка, и explicit можно опустить. А Vector(10) — динамический массив из 10 элементов ≠ десятке, тут explicit нужен.
    Ответ написан
    1 комментарий
  • Динамическая структура данных. Что это?

    @Mercury13
    Программист на «си с крестами» и не только
    Инструментом для этого, опять-таки, послужит операция new.

    Это и есть критерий ДСД. Всё, где используется динамическая память,— динамическая структура данных.

    Так же яндексом выводится очень много задач/примеров, где дсд применяется к Стеку. В итоге получаем структуры и стек.

    Почему только?
    По организации: одиночный объект, массив, разные виды деревьев, связанный список и комбинации всего этого…
    По семантике: одиночный объект, индексный массив, ассоциативный массив, список, стек, очередь, pimpl (указатель на реализацию), динамическая строка…
    Например, ассоциативный массив (семантика) можно реализовать как дерево поиска (двоичное дерево), а можно как хэш-таблицу (расширяемый динамический массив + куча связанных списков).
    Очередь (семантика) может быть кольцевым списком (динамический массив, возможно, расширяемый), может — расширяемым массивом из динамических массивов (так работает std::deque из C++), может — связанным списком.
    Стандартный подход к строке — динамический массив. Но что делать, если мы, например, клеим и клеим к строке что-то в конец? Или пишем текстовый редактор, где можно вписывать текст в середину? Тоже хитрые структуры.
    Задача Яндекса — проверить испытуемого за несколько минут. Сложную задачу вряд ли за это время разгрызёшь. Потому и любят простые структуры данных.
    Ответ написан
    Комментировать
  • Почему в потоке cout элементы выводятся в другом порядке?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело в том, что между точками следования (это точка с запятой, вызов функции и экономные операции &&, || и ?:) компилятор имеет право переставлять операции как хочет. Вот он и решил вычислять c++ с конца.

    В C++11 нет точек следования, есть «вычисляется прежде», но языка это кардинально не меняет.

    В C++17 это обещают поправить.
    19) In a shift operator expression E1<<E2 and E1>>E2, every value computation and side-effect of E1 is sequenced before every value computation and side effect of E2

    en.cppreference.com/w/cpp/language/eval_order

    ЗЫ. MinGW даже предупреждение выводит, что результат такой строчки явно не определён. И на классе Co тоже (см. флейм с Толстым Лорри).
    Ответ написан
  • Как объединить три одномерных массива в один?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы свалил их один за другим в один массив или вектор
    www.cplusplus.com/reference/algorithm/copy

    а затем дважды вызвал бы функцию
    www.cplusplus.com/reference/algorithm/inplace_merge

    Если массивы длины 10, 15 и 20, то…
    • Первый раз — std::inplace_merge(v.begin(), v.begin() + 10, v.begin() + 10 + 15);
    • Второй раз — std::inplace_merge(v.begin(), v.begin() + 10 + 15, v.begin() + 10 + 15 + 20);
    Ответ написан
    Комментировать
  • Не проходит компиляцию с любым текстом в TrayIcon->Hint();?

    @Mercury13
    Программист на «си с крестами» и не только
    Здесь используется расширение C++, т.н. свойства. Внешне они выглядят как поля, но при чтении-записи вызывают функции.
    Form1->TrayIcon->Hint = L"Bad";

    И ещё — название Form1 не рекомендуется, назови её как-нибудь fmMain.
    Ответ написан
    Комментировать
  • Как сэмулировать нажатие клавишы Пробел на Arduino?

    @Mercury13
    Программист на «си с крестами» и не только
    Странно: если ардуина — USB-клавиатура, то она передаёт именно нажатие физической клавиши «пробел».
    Впрочем, у вас тут стоит пробел в кавычках " ". Скорее всего, именно в этом ошибка: при плохой проверке типов, присущей Си, в функцию (которая требует char) будет передан адрес строки «пробел».

    Надо Keyboard.press(' '); или Keyboard.write(' ');. В одиночных кавычках. То есть целое число.

    Кроме того, Keyboard.press только нажимает на кнопку, и разбирай, как эту кнопку «отпустить». По крайней мере, моя «лисичка» требует именно ОТПУСКАНИЯ пробела. Как вариант — тот же Keyboard.write, который жмёт и отпускает.
    Ответ написан
    1 комментарий
  • Существует ли реализация J2ME для Java SE\С++?

    @Mercury13
    Программист на «си с крестами» и не только
    CLDC и MIDP — это всего лишь стандартные библиотеки Java ME. Первое — это штатные возможности процессора и JVM, более ограниченные, чем Java SE. Второе — доступ к аппаратуре телефона: LCDUI, MMAPI и прочее. Ещё одно отличие — т.н. преверификация классов (Java SE вычисляет информацию о классах сама, а Java ME с кастрированным загрузчиком — полагается на расчёт на настольном компьютере).

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

    Какой-то эмулятор есть в Java ME SDK. Как его настроить под нужный мобильник, я не в курсе.
    Также есть MicroEmulator: https://code.google.com/archive/p/microemu/downloads . Если вы хотите быть такой элитой Java ME, что будете писать свои драйверы (или просто встроить поддержку ME куда-то в другую программу), думаю, что MicroEmulator — неплохой тестовый полигон. Обычный ME’шник драйверов не пишет, их пишут авторы прошивок мобильников.
    Ответ написан
  • Почему компилятор выдаёт ошибку?

    @Mercury13
    Программист на «си с крестами» и не только
    Это очень старый код, задолго до 1998 года, когда C++ стал стандартом.

    Сейчас (а вот не в курсе — в C++98 или C++03) огромное количество заголовков C++ объединили в стандартную библиотеку шаблонов (STL). Так что потребуется слегка изменить код.

    1. Вместо <iostream.h> использовать <iostream>. <stdio.h>, в принципе, работает, но рекомендуется брать <cstdio>.
    2. Все функции находятся в пространстве имён std. То есть: std::cout, std::endl, и т.д. Либо, как предложил D' Normalization, using namespace std;.
    Ответ написан
    Комментировать
  • Как в c++ уменьшить память, зарезервированную под вектор?

    @Mercury13
    Программист на «си с крестами» и не только
    c++11 — shrink_to_fit.
    Ответ написан
    Комментировать
  • Наследование C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Private и protected — это когда объект скрывает, что унаследован от студента. Снаружи не виден ни факт наследования, ни отцовские поля.
    class Father {};
    class Son : private Father {};
    
    int main()
    {
        Son son;
        Father& q = son;
    }

    error: 'Father' is an inaccessible base of 'Son'

    Private и protected — скорее «хаки» и пользоваться ими не рекомендуется. Хотя, разумеется, пользуются, чтобы упростить себе жизнь. Я вижу два назначения: 1) хорошая основа для совершенно постороннего класса; 2) реализация интерфейса, которая нужна только внутри.

    Вот пример второго. Объект FileWriter реализует интерфейс Callback для своих внутренних нужд.
    #include <iostream>
    
    class Callback {
    public:
        virtual void act(int x) = 0;
    };
    
    void generateFibonacci(int n, Callback& callback) {
        int x1 = 0, x2 = 1;
        for (int i = 0; i < n; ++i) {
            callback.act(x2);
            int x3 = x1 + x2;
            x1 = x2;
            x2 = x3;
        }
    }
    
    class FileWriter : private Callback {
    public:
        FileWriter(std::ostream& aOs, int aN) : os(aOs), n(aN) {}
        void run() { generateFibonacci(n, *this); }
    private:
        std::ostream& os;
        const int n;
        void act(int x) override { os << x << std::endl; }
    };
    using namespace std;
    
    int main()
    {
        FileWriter wri(std::cerr, 10);
        wri.run();
    }

    А если реальная жизнь — то объект может быть одновременно QDialog (диалоговое окно) и QAbstractItemModel (модель данных для какой-нибудь таблицы, лежащей на этом окошке). Хотя, повторяю, это скорее хак.

    P.S. В Delphi и Java всё наследование публичное, и если нужно скрытно реализовать какой-то интерфейс или задействовать удобный класс — то только скрытым полем. Так, как в комментариях.

    P.P.S. Пример первого. Какой-нибудь Array2d скрыто наследуется от Array1d, потому что у него совершенно другой интерфейс. У Array1d — alloc(n) и operator()(i), у Array2d — alloc(m, n) и operator()(i, j). А Array1d — неплохая штука, чтобы управляться блоком памяти длиной m×n элементов.
    Ответ написан