- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
0
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}
https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/
What's happening here is that s + "World\n" allocates a new std::string, and then is converted to a std::string_view. At this point the temporary std::string is freed, but sv still points at the memory that used to be owned by it. Any future use of sv is a use-after-free vulnerability. Oops! C++ lacks the facilities for the compiler to be aware that sv captures a reference to something where the reference lives longer than the referent. The same issue impacts std::span, also an extremely modern C++ type.
Ты говоришь что s + "ХУй\n" породит настеке временную строку, на которую затем начнет указывать string_view (такой у него оператор "="), и наконец временная строка даст дуба а указатеть останется
Гей, я верно всё понял?
Видите, я знаю эти ваши плюсы, и вовсе не надо на них 35 лет писать чтобы их понимать
В стародавние времена String.substring в жобе создавал новый объект.
То-есть если у нас была строка в 231234 символов, а мы брали у нее сабстринг в 2 символа, то старую строку уносил бабайк GC, а новая была маленькая.
Очень много кода на это завязалось.
И тут Оракл (или Сан?) решил: а зачем срать в кучу? Давайте лучше мы будем держать указатель на старую строку и смищение в ней (ну и длину конечно).
Таким образом от одной большой строки смогут кормиться тысячи мелких подстрочек.
Сказано -- сделано (в седьмой джаве).
И весь жабаёбий код который думал что он филигранно вырезал три байта из строки в пару метров, стал держать эту строку навчено.
Жабаёбы получили ООМ, бросились к профайлерам, а там гигабайты строк лежат, которые они еще позавчера получили, вырезали пару чаров, и думали что все ок. А вот маленький сабстринг большую строку держит.
Как говорится мал клоп, да вонюч.
Такой бугор!
А видео есть?
Странно было бы, если бы string_view, который создан как быстрая обёртка над куском существующей строки, работал иначе.
Вот именно поэтому я за Си. Там ничего просто так не дохнет.
У каждой функции как правило внятный контракт. Иногда даже на уровне одной либы они совпадают. Но в целом, когда у тебя в проге юзается несколько либ - это лютый треш, о котором постоянно надо думать.
Или я просто отупел после крестов, где я по каждой внешней функции читаю доку ровно один раз - чтобы сделать над ней RAII обёртку?
Я не очень много писал на няшной под всякие сложные штуки, но обычно мне было довольно понятно кто за что отвечает.
Конечно, про это приходится постоянно думать. Зато мемори футпринт под контролем, не то что в жабах
В крестах его держать под контролем ничуть не сложнее, имхо.
> пример треша
Да банально - в одной либе тебе возвращают хуйню, на которой ты должен LocalFree, во второй - просто free, в третьей - HuiPizdaFree. Где-то надо самому буфер подготовить (и позвать перед этим с нулём для оценки размера). Где-то тебе вернут указатель на кишки структуры который вообще удалять нельзя. Каждая либа вроде и консистентна, но в целом по проекту выходит каша.
Вот в том же openssl даже в пределах одной либы не всегда понятно надо ли освобождать поинтер. Благо в последних версиях они эту инфу в сигнатуру функций стали включать...
Вот здесь и спасают крестообёртки и крестосмартпоинтеры.
Так и запишем - C++ это язык для подкостыливания сишечки.
https://github.com/bormand/pp_aes
> Превращает govnokod.ru в анонимную борду
Можно говносток и хуз сделать анонимными.
Только аппарат Илизарова он не снимает уже очень долго, всё подкручивает к нему шурушки.
надо всегда понимать что у тебя там копируется, двигается итд
Если есть HuiPizdaFree то есть и HuiPizdaAlloc, не?
Код получается сбалансированный:
Petux p = createPitux();
///////
dropPitux(p);
и всё просто.
Ну да, надо каждый раз изучать контракт, но мне кажется это не самое тяжкое в мире
Блядь, как у вас хватает на это памяти и внимания!? И ещё остаётся на суть задачи...
Это да, тут надо плодить абстракции чтобы они все за тебя делали
@if(c == NULL) return EXIT_FAILURE;
А разве аллокатор молча не швыряет исключение?
Хм. Погуглил. Инфы по CRT крайне мало, но я полагаю, что это обёртка над VirtualAlloc. Тогда тем более нужен обработчик, швыряющий исключение при неудачном вызове.
«new (std::nothrow)» — не швыряет, возвращает «nullptr».
«malloc»/«calloc» — не швыряют, возвращают «NULL».
Ну и j123123 привёл пример на «C», в нём нет никаких «исключений», и именно поэтому я за.
procedure malloc(var P:Pointer; Size:DWORD);
begin
P:=Pointer(GlobalAlloc(GPTR, Size));
if P=nil then
raise ENotEnoughMemException.Create('Вы соснули с заглотом');
end;
В ISO C исключений нет.
Есть рашсирение копулятора от MS на основе setjmp/longjmp
Речь вообще-то идёт о try.. catch..throw
2. в си нету try.. catch..throw
"Есть рашсирение копулятора от MS на основе setjmp/longjmp"
VirtualAlloc выделяет страницы в виртуальной памяти. HeapAlloc это реализация менеджера куч поверх этого. Она позвляет не гранулировать по страницам, но не позволяет резервировать например.
Сырцы СРТ ставятся с сдк или студией
Файл подкачки можно вообще отключить, виртуальная память никуда не денется, лишь бы RAM хватило.
https://docs.microsoft.com/en-us/previous-versions/ms810627(v=msdn.10)
When memory is committed, physical pages of memory are allocated and space is reserved in a pagefile.
memory always exist as either physical pages of memory or as pages that have been paged to the pagefile on disk
Если у тебя не хватает места в RAM то конечно операционка застолбит место в свапе.
Если же места хватает и свапа нет то место застолбится в памяти.
Ты никак не влияешь на то, куда попадет твоя страница. Этим занимается менеджер виртуальной памяти.
CRT может при старте вызвать VirtualAlloc (или ещё какой-нибудь ...Alloc) с запасом, а потом вызывать не на каждый malloc, а по необходимости. Внутри куска, выделенного VirtualAlloc, CRT может вводить свою разметку.
https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Implementati ons
Если бы функция malloc была тупой обёрткой, столько реализаций не появилось бы.
Поверх него есть много разных способов сделать кучу. Это может быть HeapAlloc в мастдае или malloc в glibc в прыщах или в CRT в пинде. Или new в крестах.
А «heap_alloc_dbg_internal» оперирует двусвязным списком вот таких штруктур:
Это вообще няшная или кресты?
Вощим в рилизе этотакая интеллигентная надстроечка над HeapAlloc, а в дебажной там много всего дебажного чтобы легче ловить баги
Это такой noexcept в старых крестах.
> Это вообще няшная или кресты?
Кресты. Микрософтный CRT на них написан.
> Суть проблемы
> В общем, оказывается, что строки содержат ссылки на родительские строки! Что??
> Это вроде бы не сильно на что-то влияет, но только до тех пор, пока вы не захотите из огромной строки вырезать маленький кусочек и оставить себе, а большую строку удалить. Ведь она не удалится. Она останется в памяти, потому что на неё ссылается новая строка, которую вы где-то сохранили, поэтому сборщик мусора не хочет может освободить память.
> Получается такая цепочка указателей:
> какой-то массив или объект -> ваша новая маленькая строка -> старая большая строка
> На самом деле всё ещё сложнее, у строки может быть несколько «родителей», но не будем усугублять.
> Issue 2869: Substring of huge string retains huge string in memory
> Tue, Sep 3, 2013, 6:47 PM GMT+3
> Status: Assigned (Open)
теперь еще про память и гц
типа зачем тратить времяна гц когд правда можно все перезапустить
гейдевы так делали когда-то
выделяли память спец области и целиком ее чистили когда уровень кончалсо
Ну это более разумный подход, большая арена по сути.
Какой IntelliJ )))
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206964525-why-does-idea-have-a-run-gc-button-
> А если выжила всего пара мелких фрагментов - можно их скопировать и ёбнуть оригинал.
Я кстати предлагал похожий вореант.
Когда сборщик сталкивается с high memory pressure он должен начинать компактизировать строки, а не вываливаться с OOM.
https://govnokod.ru/27616#comment664929