• Почему T * может работать ощутимо быстрее (~ на 25-30%) в качестве хранилища данных, чем std::byte *?

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

    Создайте 2 функции, которые отличаются только вот в этих вот местах.
    Вставьте код в https://godbolt.org/

    Смотрите ассемблерный код для двух функций.

    Может, срабатывает strict aliasing. Видя тип T сомпилятор понимает, что эта переменная не может быть изменена какими-то другими std::byte в соседнем коде и может, например, пропустить загрузку-выгрузку данных в регистр из памяти.

    Может вообще что-то другое.

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

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему можно не указывать virtual в файле реализации?

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

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

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

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

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

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

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

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

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    должна возникнуть ошибка, но по факту её не возникает.

    А ты собери свою программу с санитайзером памяти (-fsanitize=address) и будет тебе ошибка.
    Обращение к памяти за пределами выделенных массивов -- это UB, отсутствие видимого эффекта -- допустимый вариант поведения при UB.
    Ответ написан
    Комментировать
  • Почему при выводе массива в консоль пишется что-то странное?

    Nipheris
    @Nipheris Куратор тега C++
    Array-to-pointer decay.
    There is an implicit conversion from lvalues and rvalues of array type to rvalues of pointer type: it constructs a pointer to the first element of an array. This conversion is used whenever arrays appear in context where arrays are not expected, but pointers are:
    ...

    Ваш массив неявно сконвертился к указателю на int, т.к. оператор << класса std::ostream массивы выводить не умеет, а вот указатели - вполне себе.
    Ответ написан
    Комментировать
  • Почему при выводе массива в консоль пишется что-то странное?

    GavriKos
    @GavriKos
    Правильный вывод УКАЗАТЕЛЯ на начало памяти где массив содержится. А массив вы так просто не выведете
    Ответ написан
    Комментировать
  • Тип с точностью до 4 знаков C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Есть. Называется int. Вам надо хранить количество десятитысячных в числе. Иными словами, вы вместо x храните в int x*10000. При выводе делите на 10000 (и установите выводить 4 знака).

    Такие числа можно просто складывать и вычитать. При умножении надо будет результат поделить нацело на 10000 (или округлить к ближайшему, делящемуся на 10000 и потом отбросить 4 нуля). При делении - наоборот. Надо сначала домножить числитель на 10000, а потом поделить нацело на знаменатель (возможно стоит подумать об округлении к ближайшему целому).

    Upd: И вообще, раз уж разговор о C++, то можно реализовать свой класс. Там можно даже отдельно хранить целую часть и 4 знака после запятой. Если вам встроенной точности int/int64_t не хватает. Все математические операции можно переопределить и работать, как со встроенным типом. Вообще, по-умному, это называется fixed point numbers.
    Ответ написан
    Комментировать
  • Как решить проблему в коде не запускается код, основные операции над бинарным деревом?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Это не бинарное дерево. Ерунда какая-то. Обычно когда объявляют такое дерево -то считают что это
    бинарное дерево поиска. И в нем должны быть функции для расстановки узлов относительно значения Data.

    Здесь что? Непонятно. Рандомным образом раскидали? Зачем?
    Ответ написан
    Комментировать
  • Как работать с указателями?

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

    Вы же менянте местами значения int, значит временная переменная tmp должна быть int, а указатели надо разименовывать.
    Ответ написан
    Комментировать
  • Почему выводится другое значение вместо ожидаемого?

    HighTechLowLife
    @HighTechLowLife
    https://en.cppreference.com/w/cpp/language/eval_order

    2) If a side effect on a memory location is unsequenced relative to a value computation using the value of any object in the same memory location, the behavior is undefined.

    cout << i << i++; // undefined behavior until C++17
    a[i] = i++;       // undefined behavior until C++17
    n = ++i + i;      // undefined behavior
    Ответ написан
    Комментировать
  • Почему появляется такая ошибка?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    что тут неправильно?

    для однозначного ответа на этот вопрос не хватает определения типа Student.
    Но судя по тому как всё падает, в Student есть не-POD поля, выделяющие и освобождающие память, например std::string или что-то типа того. Загружать их из файла просто читая записанное ранее содержимое памяти нельзя, потому что загруженные указатели будут ссылаться на невыделенную память, такие типы данных нужно по-честному сериализовывать.
    Ответ написан
    Комментировать
  • Что возвращает return в С++?

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

    Советую всем программистам на C++ хотябы почитать про ассемблер.
    Стек, регистры, вот это вот все. Тогда станет понятно, как работает процессор.

    Тогда станет понятно что "сам объект tmp" никак не вернуть. Это локальная переменная, лежащая на стеке в части, которая будет отброшена при выходе из функции. Отсюда вытекает, что вообще говоря, там должна быть копия.

    Но есть такая оптимизация, как RVO. В стандарте даже прописано, когда конкретно она гарантирована. Тогда копии не происходит. При этом компилятор вообще не создает локальной переменной. А вместо этого сразу же работает с тем местом, куда надо будет возвращать значение.

    Если код и включенные оптимизации позволяют это сделать - то копии не будет. Но в общем случае - будет копия.
    Ответ написан
    Комментировать
  • Как создать диапазон чисел в массиве от -0.1 к 0.2,используя float и после ShellSort?

    sheerluck
    @sheerluck
    #include <random>
    #include <iostream>
    
    int main()
    {
        auto n = 9;
        auto rnd = std::random_device{};
        auto gen = std::mt19937_64{rnd()};
        auto dis = std::uniform_real_distribution<double>{-0.1, 0.2};
        auto res = std::vector<double>{};
        std::generate_n(
            std::inserter(res, std::end(res)),
            n,
            [&](){ return dis(gen); }); 
    
        for (const auto& elem: res)
        {
            std::cout << elem << '\n';
        }
    }
    Ответ написан
    Комментировать
  • Почему к итератору не прибавляется единица?

    Adamos
    @Adamos
    Итератор std::list - не итератор произвольного доступа, у него нет возможности перескочить несколько элементов, реализован только переход к предыдущему и следующему. Поэтому инкремент для него существует, а сложение - нет, и библиотека начинает искать по сусекам, к чему бы, реализующему сложение, его привести.
    К счастью, не находит ничего подходящего ;)
    Ответ написан
    Комментировать
  • Почему программа загружается в разных областях памяти?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему программа каждый раз занимает различные области памяти?

    Потому что современные ОС делают это намеренно, чтобы затруднить эксплуатацию уязвимостей в ПО. Это называется ASLR: address space layout randomization. Обычно есть способ отключить ASLR глобально либо для отлаживаемых программ, чтобы добиться воспроизводимости результатов.
    Так, например, в linux это делается глобально с помощью файла /proc/sys/kernel/randomize_va_space либо командой setarch -R для одного конкретного процесса. Отладчик gdb по умолчанию отключает ASLR для отлаживаемых программ.
    Ответ написан
    3 комментария
  • Хочу начать изучать С++, с чего начать?

    @bizo-31
    Рекомендую книгу Стивена Прата "Язык программирования C++. Лекции и упражнения".
    Изучал Си по его книге - мне очень понравилось, все очень доходчиво объясняется, + в конце каждой главы есть упражнения по пройденному материалу. Думаю книга по С++ не хуже.
    Ответ написан
    Комментировать
  • Как написать цикл, чтобы рамка подбирала размер под текст на языке С++?

    gbg
    @gbg Куратор тега C++
    Любые ответы на любые вопросы
    В практике современной разработки на C++ применяют libfmt или, у кого компилятор совсем новый, std::format:
    fmt::print(
      "┌{0:─^{2}}┐\n"
      "│{1: ^{2}}│\n"
      "└{0:─^{2}}┘\n", "", "Hello, world!", 20);
    
    ┌────────────────────┐
    │   Hello, world!    │
    └────────────────────┘
    Ответ написан
    1 комментарий
  • Почему программа требует константу?

    @res2001
    Developer, ex-admin
    Наверное стоит обратится к учебнику по Си почему именно так.
    Изначально автоматические массивы в Си имели фиксированный размер, т.е. размер надо задавать константой.
    Отличие константы от обычной переменной - компилятор в процессе компиляции знает значение константы, а значение переменной нет. В процессе компиляции компилятор может сгенерировать команды для выделения памяти под массив.

    Начиная с С99 (это такой стандарт Си от 1999 года) появились VLA (Variable Length Array). Синтаксис такой же как и у обычных массивов, но они могут иметь изменяемый размер, т.е. размер можно задавать обычной переменной.
    Использование VLA влечет дополнительные расходы времени выполнения, поэтому многие принципиально не используют эту возможность (например ядро Linux). И это вполне оправданно еще и потому, что память под VLA массивы выделяется на стеке, пространство стека ограничено, а вы с дуру можете там выделить слишком большой массив, что вызовет переполнение стека.

    Большинство компиляторов поддерживают VLA, но судя по ошибке, вы используете микрософтовский компилятор. Микрософт никогда не славилась поддержкой стандартов Си. VLA в ее компилятор не завезли до сих пор.
    Ответ написан
    Комментировать
  • Почему delete вызывает ошибку?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Первая ошибка:
    char *marka_ = new char;

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

    Вторая ошибка:
    char* m = "Renault"

    Тут используется значение аргумента по умолчанию, где у вас строковая константа. Тут не происходит копирование строки, просто в переменную m сохраняется адрес вот этой вот константы, которую компилятор куда-то в памяти проложения засунет. Вы не выделяли эту память, поэтому попытка сделать delete на ней - неопределенное поведение, что в данном удачном случае приводет к крэшу.

    У вас вообще проблема тут - marka может указывать на выделенную вами в Input() память, а может указывать на переданную из вне память. Кто ее удалять должен-то? Так же в Input() вы можете переписать переданный в конструкторе указатель. А надо ли было его удалять классу?

    Я бы сделал в конструкторе всегда копирование переданной строки. Тогда можно будет передавать туда и строковые константы и использовать вот такое вот значение по умолчанию.
    Ответ написан
    Комментировать