Задать вопрос
  • Существует ли тенденция избегать size_t, если это возможно?

    Lite_stream
    @Lite_stream Автор вопроса
    где есть свой STL

    EASTL ?)

    Спасибо за развёрнутый ответ
    Хз, у меня какая-то фобию unsigned'ов из-за их хитрвых приведений, сначала к singed, потом обратно. Поэтому подумал, что не я 1 такой и что люди пытаюстя по возможности unsigned'ы, и в частности size_t не использовать
  • Существует ли тенденция избегать size_t, если это возможно?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, например, чтобы случайно не написать что-то вроде
    if ((sizeof(int) - 10) > 100)
        {
            std::cout << "Greater than 100" << "\n";
        }
        else
        {
            std::cout << "Less or equal than 100" << "\n";
        }

    Программист, в реальном коде (где -10 и 100 не являлись бы константами) ожидал бы попасть в else блок, а не if
    Не просто же так в яндекс код стайле запрещено отнимать от беззнаковых типов, насколько мне известно
  • Существует ли тенденция избегать size_t, если это возможно?

    Lite_stream
    @Lite_stream Автор вопроса
    Армянское Радио, ну ок, поищу там, может быть что-нибудь найду
  • Существует ли тенденция избегать size_t, если это возможно?

    Lite_stream
    @Lite_stream Автор вопроса
    Армянское Радио,
    floppa322, так вы все равно предлагаете прикрывать дыру газеткой, причем опасным способом. Вот родился у вас массив в 4 млрд элементов, в int его размер не уместился. В дебаге вы упадете, а в релизе у вас полезет UB, причем с возможной порчей данных, которую юзер не заметит и сохранит. Так что если уж вы нашли фатальную проблему (которую сами себе создали), нужно падать безусловно, а не только в дебажных сборках.

    Здесь компромисс нужен, ведь можно точно так же упасть из-за тех же неучтённых приведений знаковых/беззнаковых типов

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

    Ну, поскольку, гайдлайнов я не нашёл по тому же int_fast*, могу предположить, что в 99% случаях нужно использовать int_fast32 вместо int'а (из-за скорости) или беззнакового size_t (из-за приведения знаковых/беззнаковых типов), за исключением массивов, потому что скорее всего массив int будет работать быстрее массива int_fast32 из-за того, что будет вдвое меньше памяти занимать, а следовательно будет в 2 раза меньше кэш промахов. Ну и в объектах, из которых могут быть составлены большие массивы, тоже, наверное, следует использовать int вместо int_fast32 по тем же причинам. В общем скорее всего int_fast32 лучше использовать как локальные переменные, либо в объектах, но с осторожностью, когда не предполагается больших массивов из таких объектов
  • Существует ли тенденция избегать size_t, если это возможно?

    Lite_stream
    @Lite_stream Автор вопроса

    floppa322, разработчики стандарта языка не такие уж и глупцы, раз обвешали всю стандартную библиотеку этим size_t.

    Предполагаю, что это просто легаси. Ну и в любом случае, методы контейнеров вроде size(), должны возвращать такой тип, чтобы, например, на 64 битной системе можно было в вектор положить больше, чем int_64, то есть unsigned long. Но в реальности то в контенерах почти никогда столько элементов не лежит, а в свою очередь беззнаковые типы несут некоторую боль
    И size_t (cppreference.com)

    std::size_t can store the maximum size of a theoretically possible object of any type (including array). A type whose size cannot be represented by std::size_t is ill-formed (since C++14) On many platforms (an exception is systems with segmented addressing) std::size_t can safely store the value of any non-member pointer, in which case it is synonymous with std::uintptr_t.

    std::size_t is commonly used for array indexing and loop counting. Programs that use other types, such as unsigned int, for array indexing may fail on, e.g. 64-bit systems when the index exceeds UINT_MAX or if it relies on 32-bit modular arithmetic.

    И int_fast*
    (stdint.h)
    /* Signed.  */
    typedef signed char		int_fast8_t;
    #if __WORDSIZE == 64
    typedef long int		int_fast16_t;
    typedef long int		int_fast32_t;
    typedef long int		int_fast64_t;
    #else
    typedef int			int_fast16_t;
    typedef int			int_fast32_t;
    __extension__
    typedef long long int		int_fast64_t;
    #endif

    Зависят от разрядности системы (64/32). Но при этом знаковый int_fast* устраняет проблемы signed/unsigned promotion'ов, в отличие от беззнакового size_t


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

    Наоборот же беззнаковые (size_t) в знаковые
  • Существует ли тенденция избегать size_t, если это возможно?

    Lite_stream
    @Lite_stream Автор вопроса

    Построить компилятору более простой и, следовательно, более быстрый код, в котором будут отсутствовать лишние преобразования 32-битных и 64-битных данных. Особенно это полезно при работе с адресной арифметикой и индексации массивов.
    Избежать ряда ошибок при обработке большого объема входных данных, когда количество обрабатываемых элементов превышает количество UINT_MAX.
    Избежать ряда других, более специфичных ошибок.
    Сделать код более переносимым между 64-битными Windows и Linux системами, в которых используются различные модели данных. Так, например, в Linux системах для индексации больших массивов можно использовать тип unsigned long, а в Windows нет.


    Тогда лучше использовать знаковый int_fast32 нет опасных promotion'ов и в 64 битных системах работать быстро будет
  • Как сделать проверку скорости передачи\приёма данных?

    Lite_stream
    @Lite_stream
    Если делать вручную на уровне UDP, то можно (для входящих пакетов), используя алгоритм экспоненциального сглаживания, имея размер пакета, вычислить входную пропускную способность
    Для исходящих пакетов почти то же самое, нужно только в структуре для ack'ов пакетов хранить ещё его размер, и когда приходит очередной ack по алгоритму упомянутому выше вычислять значение
    Вот тут примерно описывается как там всё устроено, можно также почитать остальные его статьи, если потребуется ещё какая-то инфа по сетям
  • Можно ли объявить переменную-член класса с помощью метапрограммирования?

    Lite_stream
    @Lite_stream Автор вопроса
    Благодарю за ответ
    Только хотелось бы без специализации, чтобы код не дублировать
  • Можно ли объявить переменную-член класса с помощью метапрограммирования?

    Lite_stream
    @Lite_stream Автор вопроса
    Только тебе снова придется справляться с проблемой отсутствия поля в твоем классе и я бы хотел сперва узнать, как ты планируешь это обходить.


    ну, если someCondition false, то члена в классе не должно быть
    соответственно во всех методах, где этот член используется можно будет проверку if constexpr (someCondition)
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    Спасибо за подробный ответ. Ивиняюсь, забыл уточнить в вопросе, что контейнер по изначальной задумке не должен был быть безопасным относительно исключений, как, например, вектор


    И часто забываемый, но крайне важный пункт про проектирование. Здесь нарушен Single responsibility принцип, что возможно и породило этот вопрос. Т.е. у Вас метод по добавлению элемента может удалять/заменять элементы, что должно вызвать вопросы. Более того, вы решили за клиента вашего API (даже если это и Вы сами) как нужно обрабатывать исключительную ситуацию по переполнению. Потом например вы решите, что в одном месте стоит сложить старые элементы в отдельную очередь в другом залогировать или удалять не по одному, а сразу половину буффера. Все это потребует переписывания метода add, а зачем и почему? Попробуйте убрать эту часть кода заменив на выбрасывание исключения или вариант с возвращением успешности операции (менее грамотное решение, но это уже из области субъективной оценки) и посмотреть как увеличится прозрачность и простота написания клиентского кода для этого метода. Еще стоит посмотреть на сходное проектное решение в std::vector и его методе pop_back. Подумайте почему он не возвращает удаленный элемент?


    Тут подразумевается add() у циклического буфера, поэтому клиент знает, что метод добавляет новый элемент в хвост, затираяя старый
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,
    я накидал небольшой пример такой перегрузки шаблонов.

    Спасибо, посмотрю
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, а, ну ок, тогда в следующий раз буду держать на уме его
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, если честно не знал его, но мне кажется, что внутри там что-то вроде alignas(alignof(T)) char[sizeof(T) * itemCount]
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса

    Однако, такой код может привести к ошибке трансляции в том случае, если T является неперемещаемым. В твоем ЦБ должны присутствовать проверки на перемещаемость, копируемость и возможность размена состояний.
    Если T можно копировать, но не перемещать, использовать стоит оператор копирования.
    И только если ни копировать, ни перемещать T нельзя, следует пользоваться деструктором и размещающим конструктором.

    Я бы рекомендовал все три действия оформить в виде перегрузок шаблона функции со SFINAE, чтобы для любого T включалась только одна конкретная перегрузка шаблона.


    Не совсем понимаю что это даст (в техническом плане). А с точки зрения чтения явный деструктор + конструктор будет (по моему мнению) проще восприниматься читающим код
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, мб я что-то не понимаю, но sizeof(T) должен быть кратен alignof(T), иначе как делать массив T (и в данном случае sizeof(T) будет равен выравниванию (паддинг на 24 байта будет с конца объекта))

    То есть, разместив T по выровненному адресу Addr % alignof(T) == 0 - нужно поддержать этот инвариант для каждого элемента массива, размер T должен быть кратен alignof(T), иначе следующий адресс (Addr + sizeof(T)) % alignof(T) != 0
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, ну, я сейчас ради интереса с O3 проверил, с логами, к сожалению, компилятор не превращает assignment operator + создание prvalue в деструктор + placement new (т.к. обычный конструктор)
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001,
    Компилятор наверняка тут включит свои оптимизации и получится примерно одно и то же в обоих вариантах.

    Интуиция мне подсказывает, что заменить оператор присваивания на явный вызов деструктора + placement new у компилятора может не получиться
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,


    Также интересно понять что такое эти size и maxSize. А

    maxSize - сколько всего элементов в себе умещает циклический буфер, size - сколько в данный момент элементов в нём заполнено


    Мне интересно понять, для чего существует первый участок кода, который оформлен в if (size < maxSize) и для чего существует второй - который под первым.

    Пока size не равен maxSize, то есть циклический буфер ещё не полностью заполнен, вызывать оператор присваивания/деструктор по "мусору (который находится в buffer)" нельзя

    А так же - почему функция называется add и имеет такие параметры.

    add - добавить элемент (в контексте циклического буфера понятно, что при добавлении нового в хвосте затрётся старый)
    Параметры такие, чтобы можно было передать lvalue ссылку на объект и вызвался конструктор копирования, rvalue ссылку - и конструктор перемещения, ну и просто сконструировать объект на месте, если переданы его параметры конструктора
  • Когда narrowing conversion Не является implementation defined?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, ну, там математически в коде wide находится в диапазоне narrow