Задать вопрос
  • Как убрать предупреждение "F может быть равно NULL"?

    TrueBers
    @TrueBers
    Гуглю за еду
    Как минимум, не мешать Си и Си++, а писать на чём-то одном, и различать их.
    Во-вторых, зачем от предупреждения избавляться? Его нужно понять, почему оно появляется. Когда будет понимание, тогда всё станет на свои места.

    Достаточно предположить, что функция fopen_s внезапно не сможет открыть файл и вернёт ошибку. Допустим, файла не существует, или на его открытие нет прав у пользователя. Ты же не проверяешь возврат результата из функции открытия и пытаешься что-то записать в F, даже если функция не смогла открыть файл и вернула ошибку. А когда она вернёт её, переменная F останется нулевыем указателем или, в первом твоём случае, вообще будет обращение к неинициализированной переменной, где ты получишь неопределённое поведение. Вот оно и ругается на эту ветку развития событий.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Для решения этой проблемы по уму надо написать вот это в определении производного класса:
    using Array<T>::_size;
    using Array<T>::_capasity;
    using Array<T>::_data;


    Ответ на вопрос "почему" в С++ всегда один: "потому что стандарт":
    Non-dependent names are looked up and bound at the point of template definition. This binding holds even if at the point of template instantiation there is a better match:


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

    Надо как-то компилятору указать, где искать вот эти ваши _size и т.д.
    Например, через this-> или через using или через Array<T>::.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    С чего вы взяли, что внутри шаблона это работет? Вы его инстанциировать пробовали (объявить переменную класса Outer<int>, например)?

    Вылезает точно такая же ошибка.

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

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

    Но это плохая практика - стоит включать все, что вы используете всегда. Потому что потом вы что-то поменяете, исключив какой-то уже не нужный вам хедер отсюда, или из другого хедера, и у вас вылезет ошибка о неопределенных типах из cstdint.
    Ответ написан
    Комментировать
  • Какую роль играют float и double в скобках?

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

    float нужен вам в начале, потому что вещественные константы имеют тип double. Поэтому у eps/2.0 и 1.0 в первом цикле имеют тип double, все вычесляется в double. Преобразовав одно из выражений в float вы получаете то, что вам надо. Без этого все вычисления идут в double и ответ находится не тот. На самом деле там float при сравнении все-равно расширяется до double но на результат сравнения это не влияет в данном случае.

    Еще, вместо явного приведения типов, можно поставить f после вещественных констант, чтобы указать компилятору, что это float:
    while (1 + eps/2.0f != 1.0f){

    Тогда вычисления будут во float и ответ будет правильный.

    Во втором цикле double вам не нужен. Ведь вычисления итак идут в этом типе. Да и написано у вас там с опечаткой, вы к типу double приводите все выражение со сравнением. т.е. вы булево значение преобразуете в дабл. Потом оно назад в булево преобразуется при проверке условия циклом. В итоге это бесполезное действие.
    Ответ написан
    Комментировать
  • Какую роль играют float и double в скобках?

    Adamos
    @Adamos
    Первый float - это приведение выражения за ним к типу float.
    Вообще говоря, ненужное, поскольку сложение int и float и без этого приведения будет float.

    Второй double - демонстрация того, что писавший вообще не понимает, что делает.
    Ибо тут к вещественному типу приводится... булев результат сравнения.
    Ответ написан
    8 комментариев
  • Как запретить std:: vector перемещаться?

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

    Еще можно изменить ваш дизайн. Например, вместо vector использовать list, итераторы в котором не портятся от добавления. Или хранить вместо итераторов/указателей на элементы в векторе индексы.
    Ответ написан
    Комментировать
  • Можно в c++ ли работать с памятью через stream?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Класс std::stringstream как раз это и реализует.
    #include <stringstream>
    
    std::stringstream sout;
    sout << "some string " << 42;
    cout << sout.str();


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

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

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

    1) Проверить, что данный элемент надо удалить
    1.1) Проверить, что элемент не уникальный
    1.2) Проверить, что элемент - не первый среди одинаковых (один-то его надо оставить)
    2) Удалить элемент из массива дописав 0 в конце.

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

    gbg
    @gbg Куратор тега C++
    Любые ответы на любые вопросы
    Если без велосипедов, это https://en.cppreference.com/w/cpp/algorithm/ranges...
    Ответ написан
    Комментировать
  • Почему может быть ошибка во время компиляции?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Проблема вот тут:
    parent.resize(++n);
    glub.resize(n);
    for (int i = 1; i <= n; i++) {


    Выход за границу массива. Неопределенное поведение.
    Вы выделяете массивы длины n (увеличенного на 1) и потом проходитесь от 1 до n (увеличенного на 1). Но ведь индексы в массиве только до n-1.

    Правильно так:
    parent.resize(n+1);
    glub.resize(n+1);
    for (int i = 1; i <= n; i++) {
    Ответ написан
    5 комментариев
  • Как в деструкторе базового класса вызвать переопределённый метод?

    @res2001
    Developer, ex-admin
    Никак. Когда работает деструктор базового класса объект наследник уже не существует.
    Так что "чистите" наследник в деструкторе наследника, а базовый класс в деструкторе базового класса.
    Вот старинная статья на хабре, но, на сколько я знаю, и сейчас все работает так.
    Ответ написан
    Комментировать
  • Почему MSVC выдает ошибку что размер массива должен быть константным выражением, а Clang/GCC компилирует без ошибок?

    gbg
    @gbg Куратор тега C++
    Любые ответы на любые вопросы
    value тоже должна быть constexpr

    Без constexpr срабатывает как раз VLA, о котором пишет Александр Ананьев
    Ответ написан
    3 комментария
  • ОШИБКА: "cannot overload functions distinguished by return type alone" Что делать?

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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Простешие арифметические вычисления вам бы показали, что единственное векторное изображение с таким количеством деталей вы ничем не сможете открыть и отрендерить.
    Растровое изображение тоже скорее всего превысит допустимые размеры популярных форматов, но даже изображения, близкие к максимальным по размеру уже будут открываться и отображаться очень долго даже на современном оборудовании.
    И это ещё речь незаходила об объёме картинки такого размера и с такой детализацией.
    Именно поэтому все современные картографические программы и сайты работают не с цельным изображением, а с тайлами: квадратными (обычно) картинками, векторными или растровыми, которые стыкуясь друг с другом ормируют фрагмент карты, который в данный момент виден на экране.

    Если бы действительно стояла такая абсурдная задача, то имело бы смысл, чтобы она стала хоть немного реалистичнее, разбить, всё же, всю карту на большие куски и рендерить их отдельно.
    Тут есть два подхода:
    1) можно качать готовые тайлы и клеить из них тайлы побольше. Есть много источников, многообразие которых можно оценить с помощью ресурса https://nakarte.me/. Это, кстати, opensource-прокт и его исодники доступны на гитхабе.
    Качать тайлы можно с помощью проги SAS planetа - www.sasgis.org/sasplaneta
    2) Самостоятельно рендерить карты загрузив и отфильтровав дамп БД OSM. Это более сложный путь, но он реализцется на готовых и вплне рабочих компонентах (за исключением абсурдного и нереализуемого требования про рендер в единый файл).

    Вы бы подробнее рассказали чего хотите добиться и для чего, а вам бы тут объяснили пределы возможного и целесоообразность разных попыток реалиации этого, а ещё как лучше делать то, что вы в итоге на самом деле хотите.
    https://habr.com/ru/post/270513/
    Ответ написан
    Комментировать
  • Почему std::swap вызывает конструктор перемещения?

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

    void swap(T &a, T &b) {
      T tmp{std::move(a)};
      a = std::move(b);
      b = std::move(tmp);
    }
    Ответ написан
    8 комментариев
  • Почему Config::search у меня возвращает мусор?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Проблема вот в этой строчке:
    return str.c_str();

    Тут вы возвращаете указатель на внутренние данные у str. Но при выходе из функуции str уничтожается - это же локальная переменная. В итоге у вас получается висячий указатель (указатель на память, которой вы уже не владеете). Эту память какая-то другая часть вашей программы переиспользует и там остается что-то не ваше, выглядещее для вас, как мусор.

    Вообще, это undefined behavior - доступ к висячему указателю. Программа вполне может и аварийно завершится.

    Для решения этой проблемы возвращайте std::string. Или выделяйте char* вручную, через new[] (только не забудьте указатель потом удалить в вызывающем коде). Но лучше, конечно, возвращать string и не мучатся с ручным управлением указателями.
    Ответ написан
  • Как сократить код с подпрограмой?

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

    Ну какая разница, как у вас там переменная называется sA или sB - результат будет один и тот же.

    Да, может вы путаетесь, но аргумент в функции можно тоже переменовать. Хоть там и написано int masivA(int* a), этот a - это аргумент. Он никак не привязан к массиву a в main(). Туда можно передать и a и b и любой другой массив.
    Ответ написан
    4 комментария