Pull to refresh

Comments 61

Касательно КДПВ: я правильно понимаю, что проекции в стандарт едут полным ходом?
В C++23 добавили новый интерфейс, и теперь аллокаторы могут сообщать вам, под какое количество элементов была выделена память на самом деле.
а что насчет realloc'а в аллокаторах?
В C++23 провели работу над ошибками и добавили более могущественный инструмент if consteval:
блин 10 лет и куча новых слов чтобы исправить то, что сделали constexpr функции вместо constexpr аргументов этих функций...
На подходе std::ranges::to, который позволит произвольный диапазон сохранять в произвольный контейнер:
круто, полезно. А как решили проблему с вычислением capacity контейнера для не-sized range?
В P2186R2 убрали поддержку Grabage Collector, потому что в таком виде им всё равно никто не пользовался, он просто добавлял UB.
комитет с++ вынес вердикт что GC не нужен
И наконец, приятный багфикс от Яндекса, запрещающий конструирование std::string_view и std::string от nullptr, предложение P2166R1. Ура, больше ошибок будет отлавливаться на этапе компиляции!
это может сломать компиляцию многих проектов…
> а что насчет realloc'а в аллокаторах?
Эта идея прорабатывалась в github.com/cpp-ru/ideas/issues/28, но автор несколько подзатих.

> это может сломать компиляцию многих проектов…
В этом и смысл статических проверок — не допускать кода, который гарантированно не работает и роняет приложение в рантаймме
> комитет с++ вынес вердикт что GC не нужен
Нужен, но в том виде что был в стандарте он бессмысленен и не помогает существующим GC для C++. Там даже список сужествующих GC есть в предложении, с ссылками на статьи

В геймдеве будет, небось, как с исключениями и rtti - компиляторы поддерживают, но фичи отключены настройками сборки...

круто, полезно. А как решили проблему с вычислением capacity контейнера для не-sized range?


struct count_size_fn
{
    template <ranges::range Range>
    auto operator ()(Range &&rng) const -> std::size_t
    {
        if constexpr (ranges::sized_range<Range>)
            return ranges::size(std::forward<Range>(rng));
        else
            return ranges::count_if(std::forward<Range>(rng), [](auto const &){ return true; });
    }    
};

// useful for non sized ranges
constexpr count_size_fn count_size;


Понятно, что это хуже, чем O(1).
это не просто хуже О(1), это даже не будет работать с input ranges — которые можно прочитать лишь единожды. Такой подход сработает для bidirectional ranges, и то за линию, и то если там нигде мува нет.

Можно еще извернуться, ввести в дополнение к sized_range еще условный bound_range, который вместо size() возвращает max_size(). Например, мы знаем что str | filter(isalnum) гарантированно вернет не более чем str.size() букв. Но и в этом случае резервировать память под тысячи элементов, когда нужны единицы, будет глуповато.
это даже не будет работать с input ranges — которые можно прочитать лишь единожды.

Естественно, просто невозможно узнать его размер, если он не сам не предоставит его.
Такой подход сработает для bidirectional ranges
ещё forward ranges
и то за линию
вообще не понял
если там нигде мува нет

Было бы странно, если было бы по другому. Если вы написали std::move(range), то чего вы ожидаете?
bound_range
возможно, но, как вы и отметили, имеет ограниченное применение.

По моему опыту портирования с ranges.v2 -> ranges.v3 мне потребовалась только эта функция, поскольку концепт forward range перестал требовать size().

Я перечитал ваш исходный вопрос и понял, что мы говорим немного о разных вещах. Я никогда не слышал о «проблеме capacity контейнера для не sized range» и, мне кажется, здесь нет никакой проблемы. В общем случае случае задача получения size() не может быть решена, иначе все range были бы sized.
В общем случае случае задача получения size() не может быть решена

Вот именно, так зачем вы сводите задачу получения capacity (которая не требует однозначного ответа) к задаче получения size (которая такой ответ требует)?

Выглядит интересно. Но что насчёт основных ожидаемых фич? Экзекуторы и нетворкинг всё же успевают к С++23? На рефлексию, я так понял, надеяться смысла нет.

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

Работа по executors кипит, все хотят успеть к C++23. Пока не понятно, удастся ли github.com/cplusplus/papers/issues/102#issuecomment-741483424. Networking ждёт Executors, но там практически всё готово. Рефлексия продвигается медленно, есть риски.

spanstream не копирует буфер. Полезно, например, если вы получаете по сети большие объёмы данных в какой-нибудь std::vector&ltstd::byte>, а потом разбираете его на части с помощью iostreams.
Там же где и pattern matching, flat_set, copy elision, hash_combine, wide_int, constexpr regex, constexpr аргументы функций…

Всё в разработке.

Хорошая новость — вы можете помочь комитету:
* Если умеете разрабатывать компиляторы — помогите в реализации прототипов core language идей
* Можете взять TSы, поэкспериментировать с ними, найти проблемы и предложить способы их решения (та же рефлексия выходит в виде TS github.com/cplusplus/reflection-ts )
* Можете стать спонсором комитета isocpp.org/about/membership, чтобы комитету было проще организовывать встречи и закупать переходники/проекторы/стулья/хостинг
* Наконец, можете взяться за написание прототипов и предложений для популярных идей github.com/cpp-ru/ideas/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22

Резкую отхватить минусов, но всё же спрошу.

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

После кучи видео и книг, какой-то сумбур в голове, а код всё ещё на уровне С с классами.

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

Если хочется попрактиковаться — есть курс от Yandex и МФТИ. Теория доступна любому зарегистрированному пользователю, практика по платной подписке.

Уверен, что есть и другие прекрасные материалы, но эти опробованы на своей шкуре :)
А есть лекции где еще и освещен вопрос организации исходных кодов, особенно когда его много и с ним работают не в одиночку.

А что там с легковесной заменой исключений? Чем всё дело закончилось?

Прочитал ответ страуса, ну весь текст можно свести к двум предложениям. Первое, в моём мире трава зеленее, я художник у меня есть справка, мои исключения и так почти зае..., а все доказательства против подлог и провакация, и вообще у моих эксепций право первой ночи, надо просто немножко допилить напильником. Это подавляющая часть текста, которую можно игнорировать ничего не потеряв.

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

Факт существования раста в котором эта идея воплощена в реальности и где новые эксепции имеют право первенства показывает, что все хорошо работает вместе, паника это такая же эксепция как в цпп, ну слегка усеченная и поэтому немного более эффективная да и кого вообще волнует производительность паники?

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

Есть ещё пара ключевых моментов:
* «легковесные исключения» замедляют hot path лишними if
* они используют доп регистр для флага об ошибке, что замедляет вызовы функций

В итоге — предложенные исключения кидать дёшево и они полезны при частых ошибках, но вот для ситуаций когда ошибки редки — они вредят. Кстаи, где-то была на хабре статья, где сравнивали производительность кодов возврата vs исключений, и исключения побеждали.

Вы так об этом говорите как будто это факт. Давайте я включу режим страуса и использую его же риторику только поверну стрелочку в другую сторону.

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

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

И ещё, а мужики то и не знают что оказывается то на си коды ошибок тормозят, то то они дураки все айпиай делают на кодах. Опять же в том же расте ничего почему то не тормозит. А почему тогда на си++ тормозит, не из за эксепций ли?

То что коды ошибок замедляют основной flow выполнения лишними if и что для возврата флага понадобится доп регистр — это факт.

Кстати нашел ту статью с замерами habr.com/ru/company/ruvds/blog/533332
… что для возврата флага понадобится доп регистр — это факт.
вопрос в том, какой именно регистр. Вроде как call convention использует не все x64 регистры, и передать аргумент в одном из оставшихся не должно быть проблемой?

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


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

А не могли бы ссылку дать на сравнение исключений и кодов возвратов. Очень интересно, особенно в контексте встроенного ПО для микроконтроллеров.

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

А всё увидел, ваш комментарий ниже. Спасибо.

Спасибо. Обидно что есть фрагментация сообщества — библиотеки которые хотят работать с (no-exception) и другие активно использующие их. И между ними ставят костыли. Согласен с N+1.

Планируется ли замена posix чем-то более гибким? Что бы можно было контролировать ход выполнения кода, доступ и потребление ресурсов. Или каменный век продолжиться, но будет еще больше UB, костылей и новых устаревших умных указателей.

ps: что мешает подход opencl внедрить в c++ что бы можно было компилировать и объединять несколько ядер и пускать их на исполнение совместно (современные процессоры просто умоляют об этом).
А при чем posix к c++? Используйте стандартную библиотеку, там никакого позикса нет.
Каким способом ограничить время исполнения например чтения из потока 20мс и объём максимального допустимого объёма памяти, подгружаемой библиотеке. Как штатно сделать хуки на вызовы стандартной библиотеки?
C++ — язык кроссплатформенный, как бы. И его стандартная библиотека предоставляет сервисы которые доступны на разных платформах.

Например, я не знаю способа ограничить объем памяти для подргужаемой библиотеке ни под виндовс, ни под линукс. Расскажете как?

Я уж молчу о том, что существуют платформы где библиотеки вообще линкуются только статически.
Например, я не знаю способа ограничить объем памяти для подргужаемой библиотеке ни под виндовс, ни под линукс. Расскажете как?

Очень просто надо попросить эту библиотеку использовать только ваш runtime которой ей и передать, что бы она выделяла память, создавала потоки, подгружала другие библиотеки, обращалась к файловой системе, запрашивала время и работала со строками и другими ресурсами, только через апи которое ей передали, а не напрямую через статические методы и прямые вызовы к ос.

Ну так это можно сделать на любом языке. Я вообще не вижу чем C++ такой особенный и почему ему для этого нужны какие-то специальные фичи.


Например, я видел такие либы для чистого C. При инициализации контекста они просят указатели на malloc, free и иже с ними. Можно передать библиотечные, можно — свои собственные.

Проблема в том что этого нет из коробки и все строят свои велосипеды. Из коробки есть только POSIX. Что мешает учесть ошибки и выкатить что-то более удобное.

А у C++ просто еще больше геморроя с динамическими библиотеками. Не только потому что нельзя экспортировать compile time код в динамическую библиотеку, или понять какой она runtime использует, но даже потому что так нет единого метода манглить имена с типами параметров и ограничениями концептов.

Во-первых, как я уже говорил ранее, POSIX у вас из коробки нет. Вы прекрасно можете писать на C++ под DOS или Windows, обходясь без позикса вообще. Вы случайно не путаете POSIX и стандартную библиотеку? Это разные вещи. Грубо говоря, ifstream — это STL, fopen — это libc, простой open (вы им наверное и не пользовались ни разу) — это как раз POSIX, CreateFile — это win32. Ну и в MS-DOS для открытия файла вам нужен какой-нибудь условный int 21h. Так вот, из всего этого многообразия только ifstream имеет отношение к C++. И то, не к самому языку, а к его стандартной библиотеке.


Во-вторых — я не видел ни одного языка где есть стандартный способ передачи оберток над рантаймом в библиотеки/модули. Поэтому я и говорил что было бы странно хотеть этого в C++.


В третьих — поддержка динамических библиотек, symbol name mangling и все такое — это не часть C++. Можете открыть стандарт и почитать. Там вообще ничего про это нет. Это все детали реализации. Ну и очевидно что вендоры компиляторов тут извращаются как хотят.


dl (и его виндовый аналог) был создан для того чтобы линковать программы на C (хотя, опять же, динамическая линковка не является частью стандарта С). А С++ просто "паразитирует" на этом, страдая от того что функциональность dl покрывает только задачи С. Например, манлинга имен по хорошему вообще не должно быть. Если бы dl создавался конкретно для С++, то там символы идентифицировались бы совсем по-другому.

Во-первых, как я уже говорил ранее, POSIX у вас из коробки нет

Есть стандартная библиотека, которая привязана к POSIX гвоздями.
Выделение памяти, доступ к файлам и файловой системе, создание потоков, сеть, юникод и локали, время, запуск процесов… Неужели это мене важно чем контейнеры или корутины и новые UB?

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

Во-вторых — я не видел ни одного языка где есть стандартный способ передачи оберток над рантаймом в библиотеки/модули

Посмотрите maple MKernelVector, lua lua_State, java JNIEnv да просто местами называется Context.

В третьих — поддержка динамических библиотек, symbol name mangling и все такое — это не часть C++

Так что мешает дабавить функии и которые будут работать с этими именами. Если само кодирование не стандартизовано, то почему нельзя хотя бы методы для работы с ним не описать? Что бы они были из коробки.

dl (и его виндовый аналог) был создан для того чтобы линковать программы на C

Что мешает стандартизировать дополнительные функции в динамических библиотеках которые будут решать эти проблемы? cpp_init, cpp_done, cpp_query…
Есть стандартная библиотека, которая привязана к POSIX гвоздями.

Я конечно не держал свечку, но практически уверен что имплементация стандартной библиотеки C++ для MSVC вообще никаким образом не сделана поверх POSIX.


Выделение памяти

есть в STL


доступ к файлам

есть в STL


файловой системе

есть в STL начиная с C++17


создание потоков

есть в STL начиная с C++11


сеть

обещают в следующем стандарте


юникод и локали

libicu по субъективным ощущениям больше чем весь STL. Делать юникод частью стандарта C++ — ну не знаю...


время

std:time


запуск процесов

Довольно сильно зависит от платформы. У fork/execve API и поведение сильно отличается от CreateProcess.


lua lua_State, java JNIEnv

Это вроде API для работы с внешними компонентами, а не с модулями языка. Вообще я не сильно знаком с java — можно ли загрузить Java class с другим JNIEnv?


Так что мешает дабавить функии и которые будут работать с этими именами.

Что мешает стандартизировать дополнительные функции в динамических библиотеках которые будут решать эти проблемы? cpp_init, cpp_done, cpp_query…

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

Вводить же правильно — это работы комитету на несколько лет. Кстати, может это будет сделано в рамках работы модулями?


Вместе с модулями нет шансов протащить.

В РГ21 есть идея по динамической загрузке, и есть даже proposal github.com/cpp-ru/ideas/issues/2. Комитет правда холодно воспринял идею, она пока на паузе. Попробую опять через годик, другой.
Вы не поняли о чем я говорю. Я говорю о другом ABI котрые явно бы просил программу использовать апи которое ей динамически передают и только через него общаться с внешним миром. Соответственно мы сразу получаем механиз полного контролья над модулями которые соблюдают этот контракт, т.к. можем передавить им другой ранайм который мы можем контролировать (мокать, ограничивать функционал или записывать все действия).
Вы не можете в STL вызвать подпрограмму и запретить её использовать динамическую память или попросить использовать свои методы доступа к файловой системе.

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


Если мне вдруг понадобится такая штука — то как вы правильно сказали — всегда можно передавать явный контекст со всеми нужными функциями (как JNIEnv, ага). Вы вроде упомянули явное следование контракту. С 3rd party компонентами конечно так не получится. Но там вообще никто не может гарантировать что они не будут вызывать mmap(MAP_ANONYMOUS) или VirtualAlloc(), например.

Вы вроде упомянули явное следование контракту. С 3rd party компонентами конечно так не получится.

Это почему же? Если 3rd party компоненты собирать с этой новой библиотекой и требованиями то всё будет. Посмотрите на android они именно туда идут.

mmap(MAP_ANONYMOUS) или VirtualAlloc(), например.

Они будут запрашивать динамические модули через только через переданное им апи и функции mmap и VirtualAlloc вы сможете этому модулю не давать или просто определить что он их вообще хотел и сколько раз и как вызывал. В общем песочница грубо говоря. Вы можете управлять доступом в рамках вам предоставленного как вам хочется.
Они будут запрашивать динамические модули через только через переданное им апи и функции mmap и VirtualAlloc вы сможете этому модулю не давать.

Ну если они будут запрашивать и вообще вести себя прилично — то конечно можно и не давать. Но вообще мы не можете запретить коду на C++ вызвать любой syscall по своему желанию.


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


И вообще, получится что каждый "правильный" модуль не сможет вызывать стандартную библиотеку напрямую (сейчас то добрый линковщик подставляет нужные адреса прямо в код), нужно будет делать indirect call каждый раз. Современные предсказатели переходов вроде бы справляются с этим, но все равно — лишнее случайное чтение — это не очень хорошо. Эти контексты просто не будут вылезать из кешей, мешая процессору закешировать что-то действительно важное. Короче, тут очень далеко до zero cost abstractions, которыми славится C++.


И все ради чего? Чтобы программист мог раз в жизни захукать вызовы к STL? Ну используйте LD_PRELOAD если вам жизненно важно делать хуки к стандартным либам. Немного магии с __builtin_return_address и вы даже будете знать какая конкретно библиотека пытается вызвать ту или иную функцию. А дальше — делайте любую диспетчеризацию вызовов, которые захотите. Да, непереносимо, зато не портит производительность другим юзерам.


А уж если у вас есть возможность пересобрать модули, то GCC-шная фича -finstrument-functions позволит еще и не такие чудеса творить.

Стандарт C++ работает не только с POSIX системами, рарвитию C++ POSIX не мешает.

А чем запуск разных потоков не «объединение и запуск нескольких ядер»?
Запуск разных потоков и объединение ядер это совершенно разные подходы для распараллеливания и оптимизации кода. Сопрограммы и гипертрединг призваны решить проблемы простоя конвейеров процессора в ожидании готовности памяти. Если же вы оперируете вычислительными ядрами и конвейерами которые их применяют у вас совершенно другие возможности для оптимизаций. Например появляется возможность объединять несколько ядер в одно.
Приведите пожалуйста примеры объединения ядер для x86 архитектуры. Как это должно выглядеть в C++ коде и что должно происходить на процессоре?
Пердставте у вас есть код
void a(...) { a1;a2;a3;… }
void b(...) { b1;b2;b3;… }
void c(...) { c1;c2;c3;… }
это некоторые вычислительные ядра, которые выполняют вычисления в зависимости от входных индексов (как правило матриц) и могут выполняться независимо в разном порядке и на разных ядрах.
d=merge(a,b,c)
новое ядро d которое строиться из команда a,b,c порядок которых можно варьировать в зависимости от загрузки вычислителей процессора (как hyper-threading только на уровне компилятора) т.к. они совершенно независимы.
Если писать подобное вручную, то сложность такого кода быстро превысит возможности человека. Такие ядра проще сделать примерно одной длинны и сделать что бы они работали на полях схожих размеров, чем обычный линейный код.
Лучше всего это должно выглядеть на эльбрусах и итаниах.
Вообще стандарт C++ позволяет такое делать компиляторам хоть сейчас. Такой подход хорошо ложится на архитектуру GPU, но очень плохо ложится на x86. Именно поэтому и не реализовывал никто.
нет. я описал метод распараллеливания, который имеет больше степеней свободы. вы можете изменять последовательность выполнения a1;a2;c1;b1;b2;c2;c3;..., а так же объединять векторными инструкциями отдельные части ядер. В обычном линейном коде вы не сможете получить такую плотность команд, из-за невозможности человеком комбинировать несколько алгоритмов из-за экспоненциального роста сложности.
Пока особо никаких, разве что синтаксис немного меняют. Метаклассам в первую очередь нужна рефлексия для работы
Есть ли в современных плюсах стандартный опрос событий? Или все также — юзай апи своей системы(типа poll у линукса) или фреймворк?
Никто не предлагал опрос не сетевых событий добавить в стандарт. А для чего вам понадобился такой механизм, отдельно от фреймворков?
Просто поинтересовался. Ведь std thread сделали, который также использует pthread в линуксе, емнип. Да и кроссплатформенности прибавилось бы. В целом, использование сишных системных вызовов в плюсовом коде немного угнетает, особенно в попытках сделать код плюсовым, а не сишным.
Если интересуют сетевые события, то работу с ними добавят в Networking TS. Под капотом на Linux как раз будет poll/epoll.

Но Networking не примут, пока не договорятся об интерфейсе Executors.

А как вы себе это представляете? Это очень ОС-зависимый механизм.

Что-то типа кросс-платформенного сахара, как std thread?

Порой этот сахар может быть чересчур толстым.


Для потоков — в 2020 году — ещё можно выделить какой-то общий набор возможностей и предоставить сравнительно тонкую кроссплатформенную прослойку. Для событий — пока ещё не очень.


Если производительность не важна, то берите любую библиотеку для POSIX-совместимости, там есть какая-то реализация select() или poll(). Правда, она не масштабируется на тысячи сокетов и из глаз может пойти кровь, если вы её будете читать, но работает же. Пользователи приложений на Электроне может даже схавают. Только зачем такое же тащить в стандарт — не понятно.


Ведь хотелось бы не такое же, а универсально лучшее. Чтобы как WaitForMultipleEvents(), epoll(), kqueue() — только всё сразу и с одинаковой семантикой и примерно одинаковой производительностью и масштабируемостью на всех платформах.

Вы только что описали библиотеку ASIO, которая является основой для Networking TS и должна стать частью стандарта C++.

Так что для сетевых событий решение есть, и оно на пути в стандарт.

Нет решения для событий оконных, файловой системы, событий устройств, системных нотификаций (наподобие dbus).

А не планируются какие-то удобства по корутинам? В текущем виде страшновато их трогать, много всякого вокруг накрутить надо чтоб завелись

аллокатор выделит память не под 200 байт, а под 224

Почему?

Sign up to leave a comment.