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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам надо описать конструктор Ball без параметров. Например:
    Ball() x(0), y(0), r(0), vx(0), vy(0) {}

    Потому что new Ball[n] Создает n объектов, но конструктора по умолчанию (без параметров) у класса Ball нет. Обычно его генерирует компилятор сам, но только если вы не указали никаких своих конструкторов. А new не знает, какие числа передавать в качестве x, y, r и т.д.

    Смотрите правило трех.
    Ответ написан
    Комментировать
  • Как конвертировать steady_clock::time_point в system_clock::time_point и наоборот?

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

    Вообще, если вам надо эти двое часов переводить в друг друга, то вы что-то не так делаете.
    Ответ написан
    Комментировать
  • Как сделать перестановку с повторением в C++?

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

    Вот есть статья на хабре, даже с кодом, правда на go.

    Но сам алгоритм там простой, без труда переведете на си++.
    Ответ написан
    9 комментариев
  • Ошибка вывода списка C++?

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

    Ошибка об этом и говорит, что никто не реализовал оператор << для списка.

    Если вы хотите выводить список, вам надо руками реализовать этот вывод. Циклом пройдитесь по всем элементам и выводите их, разделяя пробелами или чем вам там надо.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Figure** figure_colletion = new Figure * [this->collection_size];


    Вот тут в конструкторе вы заводите локальную переменную (с тем же именем, что и член класса) и что-то с ней делаете. Она "затенняет" член класса. А вот figure_colletion, к которому вы обрашаетесь в методе select_new_figure() - это уже член класса, который вы нигде не выделили и ничем не заполнили.

    Поэтому любой уважающий себя стиль форматирования кода подразумевает, что члены класса должны быть приватными и как-то по особому именоваться (например, заканчиваться на "_", или начинаться с "p") тогда бы вы этой ошибки не совершили. Еще можно включить предупреждения при компиляции.

    И еще, писать в методах this-> перед каждым обращением к члену класса не обязательно.
    Ответ написан
    1 комментарий
  • Как получить адрес памяти переменной в массиве, а не адрес индекса массива?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Все правильно: выводится адрес элемента в массиве. Они два не совпадают, потому что в figure_collection лежит копия line, со своим уникальным адресом в памяти.

    Edit: и вы через массив к исходному line никак не обратитесь, только если не смените тип массива на Figure*
    Ответ написан
    Комментировать
  • Как сделать динамическую подгрузку кода?

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

    defineCode(std::cout << 13 << std::endl); // work
    Работает, потому что тут макрос просто подставляет код в скобках вместо себя и он компилируется и выполняется.

    defineCode(stringLine); заменяется просто на stringLine, что есть бессмысленное выражение, вырезаемое еще на этапе компиляции.
    Ответ написан
    Комментировать
  • Как работать с большими числами в C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Если числа такие большие, что ответ никуда не влезает, то надо писать длинную арифметику. Цифры числа храните в массиве, складывайте/умножайте в столбик. Удобно хранить числа развернутыми. Гуглите "длинная арифметика" - найдете и код с примерами и кучу статей.

    Но вам это, скорее всего, и не надо. В комбинаторных задачах часто все сокращается и можно получить ответ не считая очень большие числа.

    Ваш код так ужасен, что я не могу понять, что вам там надо подсчитать в итоге, но уже брасается в глаза, что у вас там считается число сочетаний. Во-первых, можно считать (n-k+1*k+2*..*n)/k!, что уже дает более мелкие числа.

    Потом, можно считать треугольником паскаля. Можно даже считать только одну строку, домножая и деля на одно число - тоже не получая в процессе чисел больше ответа.

    Если bills не больше 64, то все влезет в стандартный unsigned long long.

    Примеры дальше в вашей задаче точно не нужны, но для кругозора опишу и их.

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

    Еще более продвинутый метод: считать по модулю больших простых чисел и в конце, через китайскую теорему об остатках вычислять ответ.
    Ответ написан
    Комментировать
  • Вылетает программа на C++ с кодом -1073741571 (0xC00000FD)?

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

    А так вижу несколько ошибок. Обычно дерево отрезков реализуют только на массиве длинной в степень двойки. Добейте a нулями, до степени двойки. И тогда массив t может быть только в 2 раза больше a, а не в 4.

    Далее, при реализации get надо, если отрезок вершины лежит внутри отрезка запроса, возвращать t[v]. в противном случае надо запускаться слева и справа, но тольо если запрос торчит в нужную сторону. Вы не запускаетесь от левого сына, если l > m, например. Можно считать значение 0, если рекурсивного вызова нет. В конце берете gcd двух половинок.
    Ответ написан
  • Как правильно передать двойной массив из класса наследника C++?

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

    Варианты решения:
    - вынести эту костанту куда-то, например сделать ее глобальной.
    - сделать Box::box static const (или constexpr - инче сами числа надо будет вынести вне объявления класса)
    - использовать Box::box в теле конструктора. Но тогда надо сделать конструктор по умолчанию для Figure и вызывать fill_figure в конструкторе Box.
    - создавать значение массива прямо в вызове конструктора Figure из Box:
    Box() : Figure( (const bool[4][4]){
          {0, 0, 0, 0},
          {0, 1, 1, 0},
          {0, 1, 1, 0},
          {0, 0, 0, 0}
      }, "Box") {};


    Лучше, конечно, завести static const.
    Ответ написан
  • Что происходит с string при передаче ссылки строки в структуру, почему может крашится?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    brick = (OBJECT*)realloc(brick, sizeof(*brick) * brickLength);


    Вот этот код вызывает ошибку. Вы выделяете стурктуру OBJECT через realloc. Но она не POD (plain old data) - там поле url - объект std::string. А объекты нельзя вот так выделять. Надо чтобы обязательно конструктор отработал. Вообще, конечно, есть способ извратиться и вызвать конструктор руками, но это костыль.

    Вы тут намешали вещи из C++ (объекты) и вещи из C (malloc) - и это все вместе не работает.

    Правильное решение будет создавть объект через new:
    brick = new Object[brickLength];

    Не забудьте только в конце отчистить это все через delete[].

    А еще лучше, используйте std::vector<Object>.
    Ответ написан
    1 комментарий
  • Как разрешить использование только конкретного наследуемого от интерфейса, не финального класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Практически никак. Суть полиморфизма в том, что экземпляры наследников можно вставлять вместо экземпляра предка везде и все будет работать. Поэтому вы средствами языка никак не запретите передавать C вместо B (речь об указателях, естественно). Если хочется, то можно сделать виртуальную функцию, которая возвращала бы какое-то enum, для идентификации классов A,B,C (и других наследников) и уже в функции проверять, что там не передали по ошибке экземпляр C. Но логичнее было бы выделить каие-то свойства у классов (например, количество пуль в вашем примере с MultiGun) их задать в виртуальных функциях у всех классов и дальше в функции проверять, что переданный экземпляр обладает нужными свойствами. Жестко привязываться, что можно B, но нельзя C - это плохой подход. Почему нельзя? А если потом появится D,E,F - можно ли их передавать? А если они братья B?
    Ответ написан
    Комментировать
  • Имеется ли в C++ данный синтаксис?

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

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вам не только принимать числа любой длины в конструкторе, вам их хранить и обрабатывать придется. Чтобы работать с данными любой длины придумали массивы. Например, передавайте строку или std::vector.
    Ответ написан
    Комментировать
  • В чем может быть проблема не считывания с файла?

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну вот ваше последнее описание и есть решение - храните 2 стека. Вы же храните 1 стек и лишь в определенном случае заводите второй стек tmp.
    Ответ написан
    Комментировать
  • Как извлечь элементы многобайтового массива как единое число?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Лучше так делать не надо. Это UB - нарушение всяких strict aliasing, выравниваия и вообще от порядка байт в машине зависит. Лучше руками собрать ULL по частям, вроде
    for (int i = 0; i < 8; ++i) result |= byte_array[i+1] << (8ULL*i);
    или
    for (int i = 0; i < 8; ++i) result |= byte_array[i+1] << (8ULL*(7-i));


    На худой конец, если очень узкое место, надо делать memcpy из массива в &result.
    Ответ написан
    Комментировать
  • Почему явная специализация невозможна?

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

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

    Вызвана эта ошибка стандартом.
    Надо, чтобы специализация шаблона была задекларирована до любого использования:
    Specialization must be declared before the first use that would cause implicit instantiation, in every translation unit where such use occurs:
    Ответ написан
    1 комментарий
  • Уменьшается ли используемая память программы?

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

    Но вообще, делать так для экономии памяти никогда, категорически не рекомендуется. Код становится менее читаем а экономите вы на спичках. Это локальные переменные - они на стеке. Их много можно выделить только рекурсией или большими массивами (ну не объявите вы в коде миллион локальных переменных). В обоих случаях, если стека не хватает - надо или избавлятся от рекурсии/больших массивов изменением логики, или выносить их в кучу.

    Использование фигурных скобок для ограничения зоны видимости переменной действительно используется на практике, когда вам надо ограничить время жизни переменной и добиться вызова деструктора в определенное время. Так делают, например, когда захватывают мютекс в многопоточных программах - специальный класс-обертка в конструкторе его хватает, в деструкторе освобождает. И иногда не надо держать мютекс во всей функции, а только в определенном месте. Допустим, дальше идут долгие вычисления, не требующие мютекса. Тут логично мютекс освободить. Но это должно встречаться редко. Если вам в функции надо несколько раз такое проворачивать, то надо ее отрефакторить и разбить на части.
    Ответ написан
    Комментировать
  • В чём отличия языка Си и С++? Зачем нужен Си?

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

    C сейчас используется в основном там, где легаси (куча старого кода в проекте уже на C), или где очень жесткие требования к легкости окружения исполнения языка (микроконтроллеры всякие).
    Ответ написан
    2 комментария