Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, GlebZ, Вы писали:
GZ>>>>Влад. Только не надо говорить что все программирование ограничивается бизнес-приложениями. VD>>>Я где-то такое говорил? GZ>>Ты такое недвусмысленно подразумевал. VD>Телепат?
Нее, телепузик.
Просто не все есть программы для IBM PС для OS MS Windows. Я в свое время поигрался с эмуляторами технических процессоров. Там такие-же подходы какие мы применяем для бизнес-приложений не подходят. Там приходится всегда думать не об абстракциях, а о системе команд и строении памяти. А этих тварей много, и ведь кто-то их программирует.
VD>>>Одно дело знать, что такое блок памяти, а другое думать только ими. GZ>>Неее. Я до сих пор думаю ими. VD>Слабо верится.
Верь. Тут есть и плюс и минус. С одной стороны не плодю заранее оптимальный код(не путать с дизайном). С другой стороны иногда действительно обидно что приходится писать неоптимальный код(ради дизайна). Переживаю.
GZ>>И это мне помогает понять язык. И тебе тоже. VD>И как тебе помогает понять скажем идиому интерфейсов раздумья о блоках памяти? Ну, или как это тебе помогает понимать паттерны проектирования вроде Посетителя?
Дизайн — это одно. А вот циклы и рекурсии — это другое.
GZ>> А особенно помогает работать с массивами. И смотреть чтобы не было копирования больших данных. И тут абстракция не поможет. Здесь нужно иметь привычку делать так, чтобы потом кардинально не переделывать. Это в большей степени не проблема дизайна, а алгоритмическая проблема. Хотя меру тоже надо знать. VD>Я такой проблемы вообще не встречал. По-моему, и так понятно, что чем больше данных ты бестолку копируешь, тем болше времени и памти таратися зря.
Именно. А еще неплохо бы учитывать что-это стек или динамическая память. И количество циклов. И StringBuild и string в C#. И аллокация в STL. Это не должно отражаться в дизайне. Но на непосредственном уровне самого формирования кода — по-моему вещь достаточно важная.
GZ>>Мы с тобой(судя по возрасту) плоды такого обучения. И я рад что прошел школу 286 процессора и CGA экрана. VD>От части, да. И мне стоило не малых усилий бороться с этими комплексами. Не раз ловил себя на мысли, что нехочу использовать виртуальный вызов просто потому что он медленее обычного. Причем с точки зрения дизайна отказ от виртауального вызова приводил к серьезному усложнению. VD> Это смешно, но мне пришлось провести не один эксперемент чтобы осознать, что стоимость даже самого медленного виртуального вызова — это наносекунды, и что бы от него получить зримое замедление его нужно запихнуть в очень объемный цикл. Если же меня учили сначала создавать грамотный дизайн приложения, а потом уже оптимизировать по-необходимости, то таких проблем никогда не вознило бы.
После определенного момента — меня греет мысль о суперумном компиляторе. Поэтому о виртуальных вызовах вообще не задумываюсь. Но во многих случаях, как уже писал, точно также.
А насчет учебы, так получилось что я самоучка. Меня никто не учил. Все познавал сам. VD>Так вот я осознанно предалел (и продолжаю преодалевать) психологические проблемы борьбы за производительность.
Аналогично. VD>А некоторые товарищи даже не задумываются над необходимостью делать это. И то что эти товарищи старше лет на 10 нисколько их не оправдывает.
Иногда в некоторых задачах это действительно важно. Особенно связанных с математикой. Я когда-то работал на науку, потому знаю. Для большинства бизнес-приложений это действительно неважно. Для McSeem2, я думаю, это и сейчас актуально.
GZ>> Очень обучает думать. Так кто там мерял скорость GDI+? VD>Ничего. Я потом опубликую результаты измерений и боюсь многие будут удивлены в какие мифы они верили. Забегая вперед скажу, что GDI+ не так тормозна как его многие описывают. При грамотном применении эта библиотека на сильно медленнее чем GDI.
А при грамотном граф. процессоре еще менее тормозная? И похоже время достойных процессоров пришло. Новая революция прокралась незаметно. Ура товарищи!!!! Я угадал?
GZ>>Правильно действовать легко научить. Правильно думать — значительно труднее. И для системы алгоритм+доступные_ресурсы — нужно учиться думать. VD>Я не вижу потуги думать у учителя. И почти уверен, что именно этому в превую очередь научатся его ученики. Они всю жизнь будут вызимать биты из байтов. Ведь сломать привычку не так то просто. Любой кто бросал курить или переучивался печатать вслепую поймет о чем речь. VD>Я вижу, что товарищь учитель просто приципиально нежелает думать абстракциями так как они зачастую привносят накладные расходы. VD>Ведь езжу понятно, что быстрее выделения памяти в стэке быть ничего не может. Но это ведь не приводит разумных программистов к отказу от использования тех же строковых классов? VD>Я вижу следующую цепочку рассуждений. VD>Программы жрут больше ресурсов чем могли бы... VD>Надо писать так чтобы использовать минимально достаточный объем ресусров... VD>Абстракции зачастую увеличивают объем используемых ресуросв... VD>Так откажемся от абстаркций и будем долбить все в стиле С. VD>При этом, правда, приводятся примеры с использованием тормознеших sprintf-ов, ну, да сути дела это не меняет. VD>Итог один — формирование стойкой неприязни к абстракциям в следствии погони за битами.
[imho]
Нет. Давай так. Павел привел действительно верные факты если брать алгоритмы программ. После этого — он перенес выводы на уровень архитектуры. Выводы в данном контексте становятся неверны. Как бы человек давно не работает на фронтах бизнес-приложений. Ему высказали все что думали. Но тут и ты начал абсолютно верные факты для дизайна программ переносить на алгоритмы(точнее даже, не учитывать их). И теперь твои факты становятся неверными.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Sinclair, sorry, а не мог бы ты подсказать, как здесь эффективно сконкатенировать все же массив строк при том, что количество их определится в момент конкатенации? S>С массивом все вообще просто. См. string.Join.
Точнее string.Concat(). string.Join — это нечто большее чем просто конкатинация.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WolfHound, Вы писали:
WH>ИМХО лучше так
Слишком много ошибок. WH>
WH>public static string Join(IEnumerable<string> strings)
// Имя явно не соотвествует поведению. Join соеденяет строки с использованием разделителя.
WH>{
WH> ICollection<string> collection = strings as ICollection<string>;
WH> if (collection != null)
WH> return Join(collection);
// Опять же нужно вызывать Concat.
WH> int n = 0;
WH> foreach(string s in strings)
WH> ++n;
WH> string[] arr = new string[n];
WH> n = 0;
WH> foreach(string s in strings)
WH> arr[n++] = s;
WH> return Join(arr);
WH>}
// Ну, а это вообще изврат полнейший. Проще и эффективнее просто использовать StringBuilder.
WH>public static string Join(ICollection<string> strings)
WH>{
WH> ICollection<string> collection = strings as ICollection<string>;
// Какой смысл проверять ICollection<string> на то что он является сам собой?
// Наверно имело смысл приводить к string[].
WH>public static string Join(string[] strings)
WH>{
WH> return string.Concat(strings);
WH>}
// Просто гениально. А что тогда не применять string.Concat напрямую?
WH>
WH>Таким образом мы избегаем двойного копирования строк.
Не факт, что просто StringBuilder окажется сильно медленее.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это все верно, но тут ты играешь на том, что эти подстроки нужны и дальше (в данном случае будут использованы в rows). А вот когда они дальше как таковые не нужны (т.е нигде храниться не будут) — тут-то ты и проиграешь.
PD>p=strtok(myString,","); PD>while(p) PD>{ PD> printf("%d\n",p); PD> p = strtok(NULL,",") PD>}
PD>Здесь эти временные подстроки никому не нужны после печати. Если ты это перепишешь на С#, то получится
PD>int i, l=0; PD>while ((i=myString.IndexOf(",", l))!=-1) PD>{ PD> Console.WriteLine(myString.Substring(i, l-i); PD> l=i; PD>}
PD>В итоге для того, чтобы распечатать подстроки, ты создал их, напечатал, и, конечно, они стали добычей GC. А я их не создавал. Правда, строку испортил, но это уж так strtok сделана. Могу свою функцию написать, которая то же сделает, но строку портить не будет.
Блин, не могу смотреть на это торжество добра над разумом.
Ты хоть представляшь какова разница между скоростью создания объекта в GC-хипе и скоростью вывода информации на консоль? Это порядки!!! Тут временная строка вообще ничего не стоит!
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Да зачем же ? Пусть TestWord себе благополучно эту строку исследует (например, является ли слово палиндромом). Начало — p, конец — '\0', зачем мне тут подстроки в отдельный буфер копировать, когда и на месте все ясно ?
Знакток, блин... strtok модифицирует входную строку добавляя в нее нули вместо символов разделителей.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Dvorkin, Вы писали:
Д>>я прекрасно понимаю, что я сделал со string Д>>длина каждой строки и должна вычисляться один-единственный раз, если тебя хоть сколько-то заботит производительность Д>>точнее — там, где она считывается из источника.
PD>А цикл, между прочим, выполняется 10000000 раз. Просто для того, чтобы время можно было замерить. А в реальной работе если он и выполнится 10000000 раз, то уж не с одними и теми же входными строками в любом случае Так что уж будь добр свой пример переделать таким образом, чтобы 10000000 он хотя бы имитировал, что строки у него новые.
а строки у тебя откуда берутся — святой дух присылает, что ли?
как я уже сказал, длина любой строки должна вычисляться один раз — когда она считывается из базы, или что там у тебя используется. После этого ее можно сохранить в ASCIIZ строку и потом перевычислять снова на каждый чих, или сохранить в std::string и больше никогда не вычислять. Доступно?
Здравствуйте, Voblin, Вы писали:
V>Здравствуйте, ZevS, Вы писали:
ZS>>- туфли на неснашиваемой подошве (казалось бы — чего проще пустить туда резину как в авто-покрышках)
V>Один мой знакомый делает обувь "Lifetime warranty". Когда я узнал об этом ( => о том, что такое бывает), у меня был шок.
"Мне предложили вечную иглу для примуса, а я не купил. Мне не нужна вечная игла, я не собираюсь жить вечно"
Здравствуйте, Дарней, Вы писали:
Д>Здравствуйте, Pavel Dvorkin, Вы писали:
Д>>>я прекрасно понимаю, что я сделал со string Д>>>длина каждой строки и должна вычисляться один-единственный раз, если тебя хоть сколько-то заботит производительность Д>>>точнее — там, где она считывается из источника.
PD>>А цикл, между прочим, выполняется 10000000 раз. Просто для того, чтобы время можно было замерить. А в реальной работе если он и выполнится 10000000 раз, то уж не с одними и теми же входными строками в любом случае Так что уж будь добр свой пример переделать таким образом, чтобы 10000000 он хотя бы имитировал, что строки у него новые.
Д>а строки у тебя откуда берутся — святой дух присылает, что ли?
Какая разница, откуда? Другая часть программы в буфер засылает.
Д>как я уже сказал, длина любой строки должна вычисляться один раз — когда она считывается из базы, или что там у тебя используется.
Да пойми же наконец, что не об этом речь. Кто же спорит, что длина одной строки должна вычисляться один раз! Но надо все же конкатенировать 10000000 раз не одну и ту же, а разные строки. Нет у меня такой зщадачи — одни и те же строки 10000000 раз конкатенировать!
Вот сделай так, чтобы у тебя строки были каждый раз разные. В реальной задаче кто-то будет в буфер новую строку засылать. В имитации можешь просто сделать вид, что строка каждый раз новая.
Это тест, не более. В этом тесте 10000000 конкатенируется 2 строки. Для теста можно не возиться специально, чтобы буферы ("1111...","222..2" ) были различны по содержанию — не все ли равно, что конкатенировать. Но нужно помнить, что содержимое буфера при каждом проходе цикла подразумевается различным. Поэтому я и внес присваивание szFirstName и szLastName под цикл — в этом имитация и заключается, строка якобы каждый раз другая. В реальной жизни szFirstName будет указателем на буфер, в котором при каждом вызове этой функции будет новое значение, а цикла не будет вообще — он здесь только для замера времени.
Можно, я слегка вмешаюсь — в основном в части, касающейся меня ?
GZ>А насчет учебы, так получилось что я самоучка. Меня никто не учил. Все познавал сам.
Я тоже.
GZ>Нет. Давай так. Павел привел действительно верные факты если брать алгоритмы программ. После этого — он перенес выводы на уровень архитектуры. Выводы в данном контексте становятся неверны.
Я не совсем понял, где я перенес выводы на уровень архитектуры. Я везде говорю о том, что не надо использовать неоптимальные решения на уровне реализации, а не архитектуры. Грубо говоря, не использовать два массива, где хватит одного. И я не совсем понимаю, почему хороший дизайн предусматривает плохую реализацию.
ИМХО здесь получается просто вот что. Делаем хороший дизайн, но при этом не думаем о том, как это реализоваться будет. Вот здесь объект такой-то создадим, такая-то функциональность. Здесь его копию сделаем, модифицируем эту копию — тоже понятно. И т.д. Все логично, все красиво — на уровне абстракций. Только 2 копии в итоге.
А, может быть, можно было одной обойтись, а изменения отдельно записать. И совсем не обязательно в ущерб дизайну и архитектуре. Просто при разработке архитектуры вспоминать иногда, что это стоит — на уровне блоков памяти
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Да пойми же наконец, что не об этом речь. Кто же спорит, что длина одной строки должна вычисляться один раз! Но надо все же конкатенировать 10000000 раз не одну и ту же, а разные строки. Нет у меня такой зщадачи — одни и те же строки 10000000 раз конкатенировать!
PD>Вот сделай так, чтобы у тебя строки были каждый раз разные. В реальной задаче кто-то будет в буфер новую строку засылать. В имитации можешь просто сделать вид, что строка каждый раз новая.
какая разница — одна и та же, или разные? Длина строки просто вычисляется где-то в другом месте (точнее — в коде, который читает данные из базы. но это уже детали)
Конкатенация ASCIIZ строк неэффективна в принципе, вот что я пытаюсь до тебя довести. Читал историю про маляра Шлемиэля?
Здравствуйте, Дарней, Вы писали:
Д>Здравствуйте, Pavel Dvorkin, Вы писали:
Д>какая разница — одна и та же, или разные? Длина строки просто вычисляется где-то в другом месте (точнее — в коде, который читает данные из базы. но это уже детали)
Код, который читает данные из базы, длину не вычисляет. Нет такого в SQL SELECT, к примеру. Внутри себя этот SELECT на сервере я не знаю что делает, но мне на клиент в итоге строка попадает как последовательность ASCIIZ. Последовательность ASCIIZ — "сырые" данные, откуда они взялись — не важно. А в объекте string на входе конструктора эти же сырые данные (а как ты еще string сконструируешь, если не по ASCIIZ или по другому string ?), а вот в полученном объекте — уже с длиной. Т.е. длину при создании экземпляра string вычислили.
Давай простой пример, искусственный, конечно. Есть огромный файл (1GB , в нем одна текстовая строка, в конце ее , конечно, 0D0A . Я открываю этот файл, делаю на него MMF, позиционируюсь в конец файла, заменяю 0D на 0, имею таким образом строку ASCIIZ. Обрати внимание — файл я не читал. Все — у меня char* pString готов.
А теперь то же самое, но сооруди мне string из данных этого файла. И ты обязан будешь файл прочитать.
Д>Конкатенация ASCIIZ строк неэффективна в принципе, вот что я пытаюсь до тебя довести.
Да ведь во входном мире ничего другого нет. Есть некий входной массив байт (из файла, из сети, ...). Этот набор нам дают и все. И чем-то заканчивают, чтобы знали, когда остановиться.
gets банальный, например. А дальше уж наше дело — то ли string из него соорудить, длину мимоходом посчитав и время потратив, то ли не считать длину, отложить до того момента, когда понадобится (может, и не понадобится) . Кстати, в моем примере с конкатенацией я эту длину мог мимоходом вычислить.
>Читал историю про маляра Шлемиэля?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Код, который читает данные из базы, длину не вычисляет. Нет такого в SQL SELECT, к примеру. Внутри себя этот SELECT на сервере я не знаю что делает, но мне на клиент в итоге строка попадает как последовательность ASCIIZ. Последовательность ASCIIZ — "сырые" данные, откуда они взялись — не важно. А в объекте string на входе конструктора эти же сырые данные (а как ты еще string сконструируешь, если не по ASCIIZ или по другому string ?), а вот в полученном объекте — уже с длиной. Т.е. длину при создании экземпляра string вычислили.
это как раз не "сырые" данные — ни один сервер БД не хранит данные в ASCIIZ
PD>Давай простой пример, искусственный, конечно. Есть огромный файл (1GB , в нем одна текстовая строка, в конце ее , конечно, 0D0A . Я открываю этот файл, делаю на него MMF, позиционируюсь в конец файла, заменяю 0D на 0, имею таким образом строку ASCIIZ. Обрати внимание — файл я не читал. Все — у меня char* pString готов.
а потом понадобилось добавить один символ к концу этой строки, и для этого тебе придется прочитать весь этот гигабайт в поисках маркера конца. Причем — перечитывать полностью каждый раз, как тебе понадобится добавить еще одну строку к его концу.
Хороший пример ты привел, ничего не скажешь.
PD>Да ведь во входном мире ничего другого нет. Есть некий входной массив байт (из файла, из сети, ...). Этот набор нам дают и все. И чем-то заканчивают, чтобы знали, когда остановиться. PD>gets банальный, например. А дальше уж наше дело — то ли string из него соорудить, длину мимоходом посчитав и время потратив, то ли не считать длину, отложить до того момента, когда понадобится (может, и не понадобится) . Кстати, в моем примере с конкатенацией я эту длину мог мимоходом вычислить.
не во входном мире, а в той библиотеке, которой ты пользуешься
>>Читал историю про маляра Шлемиэля?
PD>Нет.
Здравствуйте, Павел Кузнецов, Вы писали:
>> Любое достойное дело и или вещь является компромисом. Бескомромисной может быть только вера и преданность.
ПК>Sorry, не могу удержаться
ПК>
ПК>Думаю, когда-нибудь ты поймешь, что это очень верный, бескомпромиссный выбор архитекторов дотнета. Выбор архитектурно-чистого решения. Решения которое позволит писать код без компромисов.
...
PD>"Мне предложили вечную иглу для примуса, а я не купил. Мне не нужна вечная игла, я не собираюсь жить вечно"
PD>(C) Ильф и Петров, цитирую по памяти
Да, но это уже после того, как комбинатор стал миллионером.
Здравствуйте, Pavel Dvorkin, Вы писали:
GZ>>Нет. Давай так. Павел привел действительно верные факты если брать алгоритмы программ. После этого — он перенес выводы на уровень архитектуры. Выводы в данном контексте становятся неверны.
PD>И я не совсем понимаю, почему хороший дизайн предусматривает плохую реализацию.
Об этом уже писалось, по моему AndrewVK очень хорошо описал Мифы о рефакторинге
. Я бы туда запихнул Миф 9 — Рефакторинг увеличивает производительность кода. Строго наоборот. Он в подавляющем числе случаев уменьшает производительность кода.
Ну например, есть у нас такая фигня:
//оптимально по производительности
int cnt=GetCount();
....
for(int i=0;i<cnt;i++){...}
....
for(int j=0;j<cnt;j++){...}
//оптимально по дизайну
for(int i=0;i<GetCount();i++){....}
.......
for (int j=0;j<GetCount();j++){....}
Вполне понятно, что второй вариант и легче читается, и легко перенести второй цикл в другую процедуру. Но с другой стороны, оптимальный код по производительности выполняет GetCount только один раз. И нельзя предугадать что будет лучше. Ну например GetCount может быть просто свойством, а может быть достаточно сложной процедурой.
Здравствуйте, GlebZ, Вы писали:
GZ>Я бы туда запихнул Миф 9 — Рефакторинг увеличивает производительность кода. Строго наоборот. Он в подавляющем числе случаев уменьшает производительность кода.
Ага. Можно даже закон вывести: для любой программы А, можно написать программу A', которая будет работать медленнее программы А.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>Хуже. Она использует __declspec(thread). Иначе, сам подумай, что будет, если ее начнут из разных потоков вызывать GZ>>Для этого достаточно одного потока.
PD>Только при некорректном использовании.
Некорректное использование — это, например, случайный реентер.
void parse_line(line* line);
void parse_text(char* text)
{
int n = 0;
char* line;
for(line=strtok(text,"\n"); line; line=strtok(NULL,"\n"))
{
++n;
printf("line #%d", n);
parse_line(line);
}
}
void parse_line(line* line)
{
int n = 0;
char* word;
for(word=strtok(line," "); word; word=strtok(NULL," "))
++n;
printf(" has %d words\n", n);
}
Всё-таки, что ни говори, а strtok — ублюдочная функция. По двум причинам:
1) у неё есть внутреннее состояние, которое можно сбить
2) типичное приложение — цикл — требует двух различных, но согласованных вызовов:
а это — провокация к технологии copy-paste и различным ошибкам (начиная с очепяток).
Можно же было запомнить pattern вместе с курсором строки — раз уж вообще что-то запоминаем.
убивающее сразу трёх зайцев:
— реентерабельно
— приложения без копипаста
— за попытку раскоцать строковый литерал компилятор надаёт по пальцам (разумеется, это обходится... но уже не так просто и бездарно)
Беда сишной библиотеки — в том, что таких глупостей там хватает. Например, функции работы со временем.
И если компилятор не поддерживает TLS (а это, в общем, геморройное дело) — то многопоточное CRT оказывается не совместимо со стандартом (в котором эти глупости есть). Пример: VxWorks.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Я не совсем понял, где я перенес выводы на уровень архитектуры. Я везде говорю о том, что не надо использовать неоптимальные решения на уровне реализации, а не архитектуры. Грубо говоря, не использовать два массива, где хватит одного. И я не совсем понимаю, почему хороший дизайн предусматривает плохую реализацию.
Ага. У тебя выходит, что любая абстракция выхдящая за пределы POD (Plane Old Data) и массивы оных является злом, так как она не эффективно использует ресурсы.
str::string? Помилуйте, он же занимает память в хипе и вообще крайне не эффективен! CString, std::vector, std::map и другие бусты с лямбдами — это может отнять пару тактов процессора! О чем вы?!
В итоге ужасный непригодный к развитию и поддерживанию код смахивающий на С-код дремучих времен. Зато море слов о эффетивности, с примерами не делающими ровным счетом ничего.
PD>ИМХО здесь получается просто вот что. Делаем хороший дизайн, но при этом не думаем о том, как это реализоваться будет. Вот здесь объект такой-то создадим, такая-то функциональность. Здесь его копию сделаем, модифицируем эту копию — тоже понятно. И т.д. Все логично, все красиво — на уровне абстракций. Только 2 копии в итоге.
Ужас то какой? Особенно учитывая что копии управляются ЖЦ, а будующем возможно вообще будут устрняться компилятором или размещаться в стэке.
PD>А, может быть, можно было одной обойтись, а изменения отдельно записать. И совсем не обязательно в ущерб дизайну и архитектуре. Просто при разработке архитектуры вспоминать иногда, что это стоит — на уровне блоков памяти
Не. Ты о копиях только на словах говоришь. А на деле твой код выливается в возню с указателями и массивами размещенными в стэке.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Дарней, Вы писали:
Д>это как раз не "сырые" данные — ни один сервер БД не хранит данные в ASCIIZ
Как он хранит — не мое дело. А вот возвращает он из без длины.
PD>>Давай простой пример, искусственный, конечно. Есть огромный файл (1GB , в нем одна текстовая строка, в конце ее , конечно, 0D0A . Я открываю этот файл, делаю на него MMF, позиционируюсь в конец файла, заменяю 0D на 0, имею таким образом строку ASCIIZ. Обрати внимание — файл я не читал. Все — у меня char* pString готов.
Д>а потом понадобилось добавить один символ к концу этой строки, и для этого тебе придется прочитать весь этот гигабайт в поисках маркера конца. Причем — перечитывать полностью каждый раз, как тебе понадобится добавить еще одну строку к его концу. Д>Хороший пример ты привел, ничего не скажешь.
Бог с тобой, зачем же ? Ты вообще с MMF знаком ? Там прямой доступ. Если уж мне надо расширить файл, то я просто создам мэппинг на размер, больший, чем текущий размер файла на требуемую величину. После чего возьму указатель, возвращаемый MapViewOfFile, приведу его к char*, добавлю к нему длину файла, получу указатель на конец данных, добавлю там что надо. Остается только закрыть мэппинг , для фала вызвать SetFilePointer и SetEndOfFile. Все. Исходный файл так и остался непросмотренным.
А даже и без MMF можно. Открываем файл, SetFilePointer на конец-1 (эта операция не читает файл), дописываем данные, закрываем файл. Все.
PD>>Да ведь во входном мире ничего другого нет. Есть некий входной массив байт (из файла, из сети, ...). Этот набор нам дают и все. И чем-то заканчивают, чтобы знали, когда остановиться. PD>>gets банальный, например. А дальше уж наше дело — то ли string из него соорудить, длину мимоходом посчитав и время потратив, то ли не считать длину, отложить до того момента, когда понадобится (может, и не понадобится) . Кстати, в моем примере с конкатенацией я эту длину мог мимоходом вычислить.
Д>не во входном мире, а в той библиотеке, которой ты пользуешься
Библотека откуда данные получает ? Не из входного мира ли ? ИМХО кроме как из входного мира данные брать вообще неоткуда . А вот чтобы из входного мира строки с длиной подавали — как правило, так не делают. А если даже и сделают, это тебе не поможет в случае со string — все равно констуктор string будет исходную строку просматривать и ноль искать. По крайней мере пока это string из STL, а не что-то в Паскале, Перле и т.д.
>>>Читал историю про маляра Шлемиэля?
PD>>Нет.
Д>http://russian.joelonsoftware.com/Articles/BacktoBasics.html
Д>не наводит на размышления?
Да в общем-то ничего интересного. По крайней мере ничего нового для себя я не нашел. Довольно наивные рассуждения, особенно забавно вот это
>Строка не может содержать нулевые байты. Так что хранить произвольные двоичные данные вроде картинки в формате JPEG в строке нельзя.
Между прочим, JPEG очень неудобно хранить так же в виде стека, линейного списка, двоичного дерева и т.д. И не надо — не предназначены эти структуры для хранения JPEG . Как и строка. Кстати, ты готов хранить JPEG в виде string ?