- 1
- 2
- 3
- 4
- 5
- 6
for (int i = 1; i <= s.Length; ++i) {
if (s[i] == '/') {
s = s.SubString(1, i) + s.SubString(i, MaxInt);
++i;
}
}
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+53
for (int i = 1; i <= s.Length; ++i) {
if (s[i] == '/') {
s = s.SubString(1, i) + s.SubString(i, MaxInt);
++i;
}
}
Кручу-верчу запутать хочу. Кто с первого раза догадается, в чём задача кода - получит пирожок с полочки.
P.S. Строки билдеровские, нумерация с 1. SubString принимает индекс начала и количество символов.
И да, я считаю это ограничение очень полезным.
?
s := AnsiReplaceStr(s, '/', '//');
или регистронезависимо:
s := AnsiReplaceText(s, '/', '//');
Зачем изобретать велосипед?
Чтобы был, ради стёба же. А настоящее решение с AnsiReplaceStr() я и так выше упомянул. Оно и для билдера и для делфи подходит, либа то одна.
> регистронезависимо
Заглавный слеш это что-то новое...
А вообще, емнип, нету.
спанч боб чтоли?
На входе характер c
На выходе 'c' != '/' ? c : "//"
2)Нахуй типизацию!
конечно же
э?
"//" - const char *
Самое ужасное то, что ты даже не понял, какую ужасную хуйню сморозил.
Даже если он работает, то подобен человеку на одноколёсном велосипеде, который может ебнуться от малейшего изменения.
Т.е. то, что 8 из 10 опрошенных сказало "на первый взгляд, этот фрагмент удаляет слеши" не является проблемой? А ведь весь этот код вполне заменяется на один няшный replace...
Так и есть. У него чёрный пояс по SubString()'ам и Pos()'ам. И он любые операции над строками в этом базисе выражал... Вот еще выдержка из того кода (набросал по памяти, не ругайте):
Подразумевает то что автор изобретает велик, но какой-то не очень удобный и медленный. А еще "8 из 10" не понимают как на нём ездить.
Изменение счётчика в цикле порождает хрупкий и откровенно херово сопровождаемый код.
> C++
Что за ебанутость?
я думал паскалевые, но двухбайтные
коу? он был мутабельный? оамама
мутабельные строки это охуенно
их удобно использовать в качестве ключа в ассоциативном массиве
Кстати! Знаете прикол про жабоебов и substring в седьмой+ жабе?
COW строки прекрасно работают ключами в ассоциативных массивах. Лишь бы контейнер их по неконстатной ссылке не отдавал, когда перечисляет свои ключи.
> substring в седьмой+ жабе
Ну да, теперь он всегда копирует байтики. Кстати, а они не оставили какой-нибудь конструктор, чтобы создавать именно view на старую строку?
Автоматом.
а вот в поцкале управление кучей было ручное, как в сишечке: getmem/freemem
я уверен был что и в дельфях было так же
Просто ващет говоря реализация автоматического рефкаунта это не оч простая задача, очень круто что борланд решил ее
Там, на самом деле, майкрософт её решил, когда COM проектировали. А в делфи просто добавили поддержку COM-интерфейсов. А обычные объекты один хрен руками контролировали...
Надо же IUnknown::AddRef делать
нет?
От языка зависит... Где прикрутили нативную поддержку COM, как в делфи или VB - там конпелятор в нужных местах сам эти вызовы втыкает.
В крестах, в принципе, тоже можно руками ничего не делать (смартпоинтеры).
Вручную AddRef дёргают разве что в няшной.
В общем я понял (благодаря тебе) что рефакаунтинг вовсе не так сложно, как я думал. Правда, в нем некоторое количество лишних действий (например inc на каждый return, если не испозовать policy как у яблока), но мне стало совсем не понятно зачем выдумали GC.
Неужели только ради циклических ссылок (которые рефкаунту обычно не разрулить)?
GC собирает объекты в ширину, RC — в глубину. Т.е. если сделать глубокое дерево, наивное RC может порвать стек когда корень выйдет из скопа. Односвязный список — это как раз такое дерево, к примеру.
Ну и GC компактификацию кучи может делать.
>>компактификацию
Это как дефрагментацию, да?
Интересно было бы совместить оба подхода, чтобы программист мог сам выбирать поведение для программы. У яблов можно было когда-то опционально включать GC, но давно уже нет
Минус - очень дорогая и недетерминированна я финализация объектов, если она вдруг понадобится.
Это не так, погугли RVO. Оптимизирующий компилятор может выкидывать лишние копирования указателей и за счет этого устранять лишние пары инкримент-декримент. Кроме того, в плюсах и в расте в язык встроена мувсемантика, за счет которой временные смартпойнтеры не копируются, а перемещаются, не меняя счетчик ссылок. Так что там даже без специальных оптимизаций со стороны компилятора не будет лишних операций с рефкаунтером при возврате указателя из функции.
Как у вас всё хорошо. стану крестобляпрограммистом, пожалуй
В крестах за счёт мув семантики и RVO лишние вызовы инкремента уйдут.
Функция Foo создала на куче объект и вернула нанего ссылку.
У объекта каунт=1, иначе бы он сразу же умер.
Взявший его код увеличил каунт на 1. Получилось 2.
А после ухода указателя из области видимости опять стало 1.
Кто уменьшит этот 1 до ноля?
function Foo() {
return new Bar();
}
в каком месте компелятор тут что воткнет?
bar = Foo();
//и тут использую bar
Он знает что есть функция, возможно в библиотеке, которая возвращает какой-то указатель.
Вот я получил этот указатель. Его рефкаунт должен быть больше ноля (иначе объекта бы уже не было), значит, увеличить должна была функция в момент создания.
Хорошо. Тогда я должен всегда уменьшать его на один как только я получил его из функции.
но что если функция его не создает, а возвращает синглтон или там static storage duration?
Как клиенту узнать -- создала-ли его функция специально для меня (чтобы я уменьшил каунтер) или нет?
На них же держит ссылку некая глобалка, не тупи.
Как этот кто-то узнает что его можно удалить?
А если это филд объекта?
Ну вот выйдет у тебя глобалка из скопа (аля конец программы) или в неё ссылку на другой объект или null засунут - тогда и удалится.
> если это филд объекта
Сдохнет объект и позовётся декремент на всех его полях, которые содержат не null ссылки. Очевидно же.
З.Ы. Вот теперь настоящий Сёма детектед.
Foo() возвращает этот объект
ты хочешь сказать что на каждый вызов Foo() будет декремент каунта?
Да, будет. На каждый, блять, вызов. Хотя конпелятор имеет право убрать пару из подряд идущих инкремента и декремента (например в b = Foo() или return Foo()), чтобы время зря не тратить.
Всё, заебало, пойду лучше в кружки поиграю.
тогда синглтону пиздец придет
его каунт станет равен нолю через пару вызовов
Я там внизу пример привел, ты бы лучше над ним подумал, прежде чем злиться.
То, о чем я говорю, называется Ownership Policy, и это совсем не так просто как вы тут с субару пытаетесь мне рассказать.
Дык он же инкрементит его каждый раз, когда отдаёт кому-то. Поэтому баланс инкрементов и декрементов соблюдается.
Да, так. Именно так работают intrusive ptr и shared_ptr в крестах.
З.Ы. Почитал этот ваш Ownership Policy - те же яйца, только сбоку. If an existing object is returned, its retain count is incremented so it is your responsibility to relinquish ownership.
Верно.
> что если функция его не создает, а возвращает синглтон или там static storage duration?
Тут есть две опции. Одна - у владеющих и невладеющих указателей должен быть разный тип. Вторая - у указателя должен быть флажок, по которому в рантайме можно узнать, владеет ли он объектом.
третье это по имени функции понимать policy: создающие объект и возвращающие существующий могут иметь разные префиксы
Как видишь автоматический рефкаунтинг не так прост, все решения не выглядят слишком элегантнор
Кстати, а как Ownership Policy в ObjectiveC дружит с многопоточностью?
По Get Rule мне вернули существующий объект и, если он мне нужен, я должен позвать CFRetain. А если за это время объект уже сдох?
З.Ы. А, ну ясно: Moreover, it is usually not possible to achieve absolute thread safety at this level. You cannot rule out, for example, indeterminate behavior resulting from retaining an object obtained from a collection. The collection itself might be freed before the call to retain the contained object is made.
Дооптимизировались. Описанная мной в этом треде политика, когда во всех случаях работает Create Rule, выглядит проще и безопасней (хотя и чуть медленнее из-за инкремента/декремента).
В принципе, subaru всё правильно объяснил.
Ну всё тривиально же:
1) new возвращает временную ссылку со счётчиком 1
2) a = b инкрементит счётчик у b и декрементит у a (если там был не null)
3) return инкрементит счётчик
4) выход ссылки из скопа декрементит счётчик
5) пару inc+dec можно выбросить, если хочется оптимизации
почему
a = b
вдруг уменьшает рефканут у b?
А если Foo() вернет ссылку на синглтон то через пару вызовов он помрет/
> ссылку на синглтон
Как он блять помрёт, если реализация синглтона держит в себе ссылку на этот объект? Чтобы её же вернуть второму клиенту, который придёт после тебя?
class Foo{
function bar(){return this}
function eggs(){return new Spam();}
}
///в другом месте////////
foo = new Foo();
foo->bar();
foo->eggs();
На последней строчке нам возвращается объект с рефкаунтом 1 и надо бы как-то его уменьшить, иначе он не помрет никоглда
на предпоследней строчке нам возвращается объект с рефкаунтом 1, но его уменьшать не надо потому что метод его рефакунт не увеличивал.
Учти что компилятор НЕ ЗНАЕТ что там внутри класса Foo происходит.
Вызовы для него одинаковы, а поведение должно быть разное.
Если он всегда будет уменьшать счетчик, то два вызова bar() разрушат объект
а если не будет -- то после вызова bar() будет утечка
Ну схуя? Поведение будет одинаковое - и после foo->bar() и после foo->eggs() он позовёт декремент (rule 4).
return this увеличит счётчик на 1 (см. rule 3), поэтому bar() вернёт объект с рефкаунтом 2 и он выживет.
return внутри eggs() тоже увеличит счётчик (rule 3), но выход временной ссылки из скопа (которую вернуло new) уменьшит его (rule 4), поэтому из eggs() вернётся объект с рефкаунтом 1 и он сдохнет.
Включи мозги уже, блин.
Что ты так разнервничался? Первый раз ламера в Интернете увидел?
Сорри, у меня синдром утёнка случился - я не знал, что в ObjectiveC используется более сложная схема рефкаунтинга, чем обычно (вот это самое разделение на Create методы, которые инкрементят и Get методы, которые не инкрементят).