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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Потому что тут разное поведение.

    Первый вариант отбрасывает дробные части от копеек, а второй отбрасывает дробные части от рублей. Ведь при делении на 100 в целых числах идет округление вниз. Если брать p процентов с округлением вниз от числа в рублях, то и получится целое число в рублях. Если брать от числа в копейках, то и получится целое число в копейках.

    Поскольку второй код отбрасывает все копейки при прибавлении, то ему требуется больше итераций, чтобы дойти до y. На самом деле он может даже виснуть, если там получается прибавление 0.
    Ответ написан
    1 комментарий
  • Как ускорить работу скрипта?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вместо сравнения каждой строки с каждой используйте структуру данных trie. В стандартной библиотеке, к сожалению, ее нет. Поэтому придется писать самостоятельно. Там в каждой вершине храните сколько строчек в ней заканчиваются. Потом сложите туда все строчки из первого файла и проверяйте каждую строчку из второго и выводите ровно столько раз, сколько в первом файле она была.

    Ну или можно использовать std::unordered_map<std::string, int> вместо trie.
    Ответ написан
  • Почему возникает проблема "terminate called after throwing an instance of 'char const*'"?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Сообщение говорит, что было брошено исключение, которое никто не поймал и поэтому программа завершилась.

    Обрабатывайте исключения (конструкция try..catch) где-нибудь в main, тогда можно будет вывести сообщение с ним связанное. Может станет понятнее, откуда оно было брошено. Или можно просто пискать в коде "throw" - скорее всего оно и срабатывает.
    Ответ написан
    Комментировать
  • Почему возникает ошибка?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    В find_in_nodes_by_name у вас return закомментирован. Это первая ошибка.

    По второй ошибке: попробуйте написать LinearNavigation<T>::haveNext() там, где оно вызывается в isFullyConnectedQuad.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Надо смотреть, что там get_childrens возвращает. Судя по ошибке, там где-то замешаны unique_ptr, которые нельзя просто копировать.

    Подозреваю, что ошибка исправится, если в for сделать item ссылкой.
    Ответ написан
    1 комментарий
  • Как передать массив вместо аргументов?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Не совсем поятно, что вы хотите сделать.

    Если вы хотите передавать массив, то поменяйте функцию f так, чтобы она его принимала.

    void f(const std::vector<int> &arg){
    }
    f({1,2,3});


    И да, массив не в квадратных скобках задается, а в фигурных.
    Передача по ссылке, чтобы не копировать эти все значения лишний раз. Для трех элементов погоды почти не делает, но если их 100, или тем более 1000 - это заметная оптимизация. const, чтобы можно было передавать временные объекты. Плюс так понятно, что это аргументы входные и вы их менять в функции не будете.
    Ответ написан
  • Как получить ввод c++ для задачи по спортивному программированию?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Число q, судя по тексту, уже дано вам в файле.
    Поэтому просто циклом q раз читайте команду.
    Там читайте одно число, и если это 1, то читайте i, x. Если это 2 - то читайте k.

    for (int line = 0; line < q; ++line) {
      cin >> command;
      if (command == 1) {
        int i, x;
        cin >> i >> x;
        UpdateValue(i, x);
      } else {
        int k;
        cin >> k;
        ShiftRight(k);
      }
    }
    Ответ написан
    3 комментария
  • Можете покритиковать мой код?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    1) (Вкусовщина) стиль наименования не самый удачный. И переменные и функции называются одинаково - каждое слово с большой буквы без разделителей. Во всех массово применяемых стилях обычно переменные, функции и константы называются по разному. Например, переменные можно называть log_password. Функции и так оставить с большой буквы, а константы - полностью большими буквами.

    2) обилие вложенных if. Практикуйте ранний выход. Например в Login() можно сделать так:
    if (Data.is_open()) {
      std::cout << "Ошибка. У вас нет аккаунта" << std::endl;
      return;
    }


    И весь оставшийся код оказывается на 1 уровень выше.

    3) Бесконечные рекурсивные вызовы - это плохо. Рано или поздно программа упадет с закончившимся стеком.
    У вас Menu вызывает Login, который опять вызывает Menu. Да и сам Menu тоже.

    Лучше сделать в Menu бесконечный цикл (while(true)) и или выходить из программы через exit(), или возвращать из Login, что надо завершаться и тогда в Menu делать break.
    Ответ написан
    1 комментарий
  • Для чего в C++ сделано описание методов вне класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это пошло еще из Си. Абсолютно тот же механизм, что используется для глобальных переменных и функций. Более того в ранних версиях Си надо было всегда отдельно объявлять функцию и отдельно ее определять.

    Используется для этих вещей:
    1) Можно иметь "циклические зависимости". Например, функция использует класс, а класс использует функцию. Или два класса используют друг друга. В каком порядке их определять в файле? Так уж повелось, что компилятору надо как-то знать о всех используемых в коде штуках до их использования (в основном). Возможность отдельно объявить функцию/класс как раз решает эту проблему. Можно было бы переделать весь компилятор, чтобы он сначала по всему файлу искал функции, но по каким-то, возможно веским, причинам это не было сделано еще в Си. А C++ потащил и это с собой.

    2) Разделение программы на "модули" или библиотеки. Этот ужасный, устаревший и неудобный механизм include-ов позволяет разбить программу на хедеры и файлы с реализацией. Потом хедеры только с объявлениями включаются в другие файлы, чтобы компилятор знал о коде в других модулях, а реализация собирается в отдельный объектный файл. В конце линкер собирает все объектные файлы в исполняемый файл и/или библиотеки. Если бы объявления и определения не были разделены, то весь код в проекте компилировался бы кучу раз в каждом объектном модуле. Это просто глупо.

    3) И вообще - это красиво. Иметь где-то аккуратный список всех методов класса (или функций в библиотеке) удобно, когда вам надо разобраться, а что этот класс делает и как его использовать. Если бы там еще и код методов был, то это было бы сложнее читать.
    Ответ написан
    Комментировать
  • STD::set erase не работает?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У вас в set хранятся указатели на char. В set они сравниваются как указатели. Как значения адресов. Strcmp же смотрит на содержимое памяти, на которую указатели ссылаются. Поэтому имея в памяти две совпадающие строки вы получите вот это вот - указатели не равны, а strcmp - равно.
    Ответ написан
    Комментировать
  • Как исправить ошибку сегментации C++ (segmentation fault)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Segmentation fault - это ошибка работы с памятью. Ваша программа вылезает за границы вашей памяти или делаете что-то не то с указателями.

    Одна очевидная ошибка - вы не уменьшаете n при удалении элемента. И тогда на следующей итерации вы будете что-то делать с элементом за концом массива.

    Еще одна ошибка у вас в том, что вы в add, например, всегда удаляете указатель на f. А в самом начале этот указатель неинициализирован. Удаление такого случайного указателя - это undefined behavior. Программа может упасть сразу, а может только на следующей итерации цикла.

    Советую инициализировать f в nullptr и перед удалением всегда проверять, что удаяемый казатель не нулевой.
    Ответ написан
    2 комментария
  • Почему вызов метода класса гораздо медленее вызова обычной функции и как это исправить?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Подозреваю, что дело в оптимизаторе. В первом примере компилятор понимает, что цикл ничего не делает и вырезает его весь нафиг. Во втором же случае, разделение на файлы не позволило оптимизатору убрать цикл. Можно покрутить опциями оптимизатора, что бы была кросс-модульная оптимизация (не помню правильное название), но в итоге вы будете сравнивать пустоту с пустотой.

    Правильнее добавить в тестируемую функцию какую-то работу. Тогда вы будуте действительно сравнивать вызов функции и метода. Или отключить всю оптимизацию.
    Ответ написан
    2 комментария
  • Зачем нужен амперсанд перед именем функции/метода?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    На самом деле понятнее писать вот так:
    int& Foo();

    Функция возвращает ссылку на int. Ссылка - это как указатель, только она не может указывать вникуда. Соответственно, вы не можете завести переменную ссылку сразу не инициализировав ее - а на что она будет указывать. И также ссылки, в отличии от указателей, не надо ее разыменовывать.

    Использовать можно, например, вот так:
    int& ref = Foo();
    std::cout << ref+10;


    Тут под переменную ref не выделяется память, ведь это ссылка, которая инициализируется тем, что вернула Foo. Так же сам объект не копируется. Максимум, под капотом скопируется адрес.
    Поэтому ссылки имеет смысл заводить на тяжелые объекты, чтобы не копировать их зря и не выделять память.

    Так же можно через эту возвращенную ссылку изменять основной объект:
    int x;
    int& Foo() {
        return x;
    }
    ...
    
    x = 0;
    int& ref = Foo();
    ref = 10;
    std::cout << x:

    Этот код выведет 10.

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

    Ну и еще, можно с этой возвращенной ссылкой работать и как с обычным int:
    int x = 2 + Foo();
    Но если вы не собираетесь менять значение внутри или не пытаетесь сэкономить на копировании объекта, то вам нет смысла вообще ссылки использовать.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    assign делает совсем не то, что вы думаете. Оно заменяет строку s на подстроку.

    Вам надо использовать s.substr.
    Ответ написан
    Комментировать
  • Как оформить список C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Используйте snprintf. Так можно с тем же форматом вывести все данные не в консоль, а в строку.
    Ответ написан
  • Как определить тип функции для шаблона?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно использовать typedef int value_type; в классе с Setter/Getter.

    Тогда в вашем шаблоне вы можете использовать C::value_type. Так в STL, например, сделано.

    Плюсы: не надо обязательно заводить n. Можно обзывать его как удобнее или оно может вообще иметь другой тип, если свойство хранится неявно.

    Минусы: Надо обязательно заводить этот самый value_type и обновлять его вместе с методами Getter/Setter.
    Ответ написан
  • Сдвиг двумерного массива, появление ошибки Stack around the variable 'arr' was corrupted. Как исправить без переписывания кода?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Код исправляется элементарно. Надо внутренний цикл по j гнать не до 0, а до 1. Что бы не вылезать за границу массива, вы же там к j-1 -ому элементу обращаетесь. А поскольку вы делаете swap, то вы меняете элементы массива с памятью перед ним. Массив - локальная переменая, а значит он лежит на стеке и вот это вот затирание памяти рядом с массивом и есть это самое "Stack around the variable 'arr' was corrupted".

    Ну и по стилю - вместо i > -1 обычно пишут i >= 0.
    Ответ написан
    Комментировать
  • Как решить задачу с символами? Почему не работает одна функция?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам надо не делать break. А сохранить куда-то текущее значения счетчика kol и также установить флаг, что вы встретили u. После цикла, который заканчивается чтением точки, надо, если флаг u был не встречен, вернуть значение счетчика kol. Иначе - сохраненное значение.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Я так понимаю, у вас проблема со строчкой
    aobj1[0] = a(2);

    Тут вызывается конструктор для временного значения a. Потом оператор копирования из временной переменной в *aobj. Потом вызывается деструктор временного значения.

    А потом где-то в конце произойдет и деструктор aobj.

    У aobj delete_counter после этой строчки равен 1 (ведь он скопирован у временного значения, которое сделало delete_counter единицей в констукторе). В конце при вызове деструктора aobj там delete_counter будет 1 в начале.

    Вы смотрите на адрес this в дебагере в деструкторе. Два вызваных деструктора будут для двух разных объектов (для временного значения и для aobj).

    Если вы хотите какой-то счетчик ссылок делать, то вам надо переопределять операторы копирования и перемещения (а так же все возможные конструкторы). И там аккуратно изменять счетчик ссылок. И счетчик ссылок должен быть частью общего объекта - частью класса b, а не класса a.
    Ответ написан
    4 комментария
  • Почему простой цикл на c++ выполняется медленнее, чем на golang?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы сами в комментариях привели дизассемблированный код. Go по какой-то причине оптимизирует код лучше - тупо выкидывает весь ваш цикл.

    Чтобы этого не было, можно ксорить не с константой, а с индексом i, например.
    Ответ написан
    Комментировать