Ищё IO-библиотеку, построенную на виртуальных классах потоков.
Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java
Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.
Здравствуйте, Cyberax, Вы писали: C>Ищё IO-библиотеку, построенную на виртуальных классах потоков. C>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java C>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.
Чем не нравятся стандартные потоки C++? Виртуальность в них вынесена на уровень ниже, в streambuf.
Здравствуйте, gegMOPO4, Вы писали:
C>>Ищё IO-библиотеку, построенную на виртуальных классах потоков. C>>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java C>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код. MOP>Чем не нравятся стандартные потоки C++? Виртуальность в них вынесена на уровень ниже, в streambuf.
Потому, что там дизайн кретенический.
1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить.
2) Мне нужен дизайн потока, а не буффера.
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>Ищё IO-библиотеку, построенную на виртуальных классах потоков. C>>>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java C>>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код. MOP>>Чем не нравятся стандартные потоки C++? Виртуальность в них вынесена на уровень ниже, в streambuf. C>Потому, что там дизайн кретенический. C>1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить.
Выше речь шла о форматированном выводе. Зачем же потоки вам нужны? Как собираетесь их использовать?
C>2) Мне нужен дизайн потока, а не буффера.
Что вы под этим подразумеваете? Потокам Jаva соответствуют буферы C++, а потоки С++ — это скорее форматтеры (или принтеры) Java.
Здравствуйте, gegMOPO4, Вы писали:
C>>1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить. MOP>Выше речь шла о форматированном выводе. Зачем же потоки вам нужны? Как собираетесь их использовать?
Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока.
C>>2) Мне нужен дизайн потока, а не буффера. MOP>Что вы под этим подразумеваете? Потокам Jаva соответствуют буферы C++, а потоки С++ — это скорее форматтеры (или принтеры) Java.
Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна.
streambuf — это абстракция буфера, в нём есть underflow/overflow, seek и прочее. Причём уже в streambuf есть поддержка локалей. Самый близкий мне аналог — это вроде бы istream, но там всё так криво, что на него смотреть даже не хочется.
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>1) Ну нафиг мне в низкоуровневом потоке работать с локалью?? Туда уже должны чистые потоки байт приходить. MOP>>Выше речь шла о форматированном выводе. Зачем же потоки вам нужны? Как собираетесь их использовать? C>Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока.
read/write, get/put. Локаль тут никаким боком.
C>>>2) Мне нужен дизайн потока, а не буффера. MOP>>Что вы под этим подразумеваете? Потокам Jаva соответствуют буферы C++, а потоки С++ — это скорее форматтеры (или принтеры) Java. C>Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна.
OutputStream — 5 виртуальных методов, InputStream — 9. Не считая конструкторов. Буферы С++ проще и эффективнее.
C>streambuf — это абстракция буфера, в нём есть underflow/overflow, seek и прочее. Причём уже в streambuf есть поддержка локалей. Самый близкий мне аналог — это вроде бы istream, но там всё так криво, что на него смотреть даже не хочется.
Пока не используете «широкие» потоки, локаль пусть вас не волнует.
Здравствуйте, gegMOPO4, Вы писали:
C>>Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока. MOP>read/write, get/put. Локаль тут никаким боком.
Про "virtual void imbue(const locale&)" забываем?
Ну давай смотреть. Смотрим класс strstreambuf, в нём реализованы:
На минимальный интерфейс ну никак не тянет.
C>>Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна. MOP>OutputStream — 5 виртуальных методов, InputStream — 9. Не считая конструкторов. Буферы С++ проще и эффективнее.
Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию.
(если бы я дизайнил потоки Java, то сделал бы их немног по-другому, но базовая идея там вполне разумная)
C>>streambuf — это абстракция буфера, в нём есть underflow/overflow, seek и прочее. Причём уже в streambuf есть поддержка локалей. Самый близкий мне аналог — это вроде бы istream, но там всё так криво, что на него смотреть даже не хочется. MOP>Пока не используете «широкие» потоки, локаль пусть вас не волнует.
Тем не менее, она есть, что мне УЖЕ не жутко не нравится. Некрасиво.
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>Мне нужно работать с потоками байтов. Опционально с форматированым выводом, с помощью форматтеров, работающих поверх нетипизированного потока. MOP>>read/write, get/put. Локаль тут никаким боком. C>Про "virtual void imbue(const locale&)" забываем?
А зачем вам imbue при работе с потоком байт?
C>Ну давай смотреть. Смотрим класс strstreambuf, в нём реализованы: C>
Это из-за того, что буфер используется и для ввода, и для вывода. Да и какое дело вам до интерфейса буфера? Его пользователь — поток, а вам он предоставляет более удобный и быстрый интерфейс read/write, get/put.
C>>>Не соответствуют. Потоки в Java состоят буквально из одного метода "write(void *data, size_t ln)", остальная функциональность добавляется в наследниках или опциональна. MOP>>OutputStream — 5 виртуальных методов, InputStream — 9. Не считая конструкторов. Буферы С++ проще и эффективнее. C>Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию.
И дёргать виртуальный метод для каждого байта. Нет, то, что допустимо в Java, в C++ совершенно неприемлемо, тем более в стандартной библиотеке. Здесь умеют считать байты и такты, и JIT не сгладит лишний оверхед. streambuf имеет виртуальные методы, но дёргаются они как можно реже. Это интерфейс, ориентированный на производительность.
Здравствуйте, gegMOPO4, Вы писали:
C>>Про "virtual void imbue(const locale&)" забываем? MOP>А зачем вам imbue при работе с потоком байт?
Так ведь нужно реализовать.
C>>На минимальный интерфейс ну никак не тянет. MOP>Это из-за того, что буфер используется и для ввода, и для вывода. Да и какое дело вам до интерфейса буфера? Его пользователь — поток, а вам он предоставляет более удобный и быстрый интерфейс read/write, get/put.
Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе?
Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.
C>>Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию. MOP>И дёргать виртуальный метод для каждого байта.
Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже.
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>Про "virtual void imbue(const locale&)" забываем? MOP>>А зачем вам imbue при работе с потоком байт? C>Так ведь нужно реализовать.
Не нужно реализовывать.
C>>>На минимальный интерфейс ну никак не тянет. MOP>>Это из-за того, что буфер используется и для ввода, и для вывода. Да и какое дело вам до интерфейса буфера? Его пользователь — поток, а вам он предоставляет более удобный и быстрый интерфейс read/write, get/put. C>Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе?
База у потоков не виртуальная. Передаются потоки по ссылке. А вот вся специфичность определяется виртуальным буффером, который задаётся при инициализации потока. В результате всё множество методов и операторов потока невиртуально и инлайнится, а виртуальные методы вызываются только когда нужно сбросить/подтянуть очередную порцию данных в буффер, раз на много операций.
У Страуструпа расписано немного подробнее, чем в Стандарте. Этого достаточно. Можете также посмотреть реализацию строковых и файловых буферов (или сторонние реализации для gzip и т.п.).
C>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.
Если вам критично по скорости/памяти создание именно на стеке и строковые потоки не подходят, то вам скорее всего нужны не потоки, а итераторы (или генераторы).
Впрочем, можно создать и буфер статичного размера. Реализация будет намного проще строкового, большинство операций останутся пустыми, всю работу можно проделать в конструкторе.
C>>>Для реализации InputStream достаточно переопределить один метод "public abstract int read() throws IOException;", остальные методы имеют реализацию по умолчанию. MOP>>И дёргать виртуальный метод для каждого байта. C>Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже.
Принцип C++ — zero overhead. Вы не платите за возможности, которые не используете. А если платите — то минимальную цену. Дёргать виртуальный метод на каждую операцию — слишком высокая цена для C++ (ведь можно дешевле). Поэтому пользователь пользуется богатым невиртуальным интерфейсом потоков (который не нужно переопределять), а уже поток внутри использует буферизацию, дёргая виртуальные методы только тогда, когда без этого не обойтись. И интерфейс этих виртуальных методов разработан для потребности потоков.
Здравствуйте, gegMOPO4, Вы писали:
C>>Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе? MOP>База у потоков не виртуальная. Передаются потоки по ссылке. А вот вся специфичность определяется виртуальным буффером, который задаётся при инициализации потока.
Ну вот как его сделать-то?
MOP>У Страуструпа расписано немного подробнее, чем в Стандарте. Этого достаточно. Можете также посмотреть реализацию строковых и файловых буферов (или сторонние реализации для gzip и т.п.).
Ага. Посмотрел. Мозг выпал.
C>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов. MOP>Если вам критично по скорости/памяти создание именно на стеке и строковые потоки не подходят, то вам скорее всего нужны не потоки, а итераторы (или генераторы).
Нельзя. Нету у итераторов общей виртуальной базы, а мне именно виртуальность нужна — чтобы библиотечный код во внешней библиотеке быстро работал с произвольной реализацией потоков.
C>>Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже. MOP>Принцип C++ — zero overhead. Вы не платите за возможности, которые не используете. А если платите — то минимальную цену. Дёргать виртуальный метод на каждую операцию — слишком высокая цена для C++ (ведь можно дешевле).
Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати.
MOP>Это ООП наизнанку. Паттерн «стратегия».
Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию).
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: C>>>Я не знаю, у меня мозга не хватает, чтобы понять всю структуру IO-потоков в С++. Где можно взять пример как их использовать, чтобы сделать виртуальный поток для неформатированного вывода, который можно создавать/уничтожать с минимальным оверхедом и передавать по виртуальной базе? MOP>>База у потоков не виртуальная. Передаются потоки по ссылке. А вот вся специфичность определяется виртуальным буффером, который задаётся при инициализации потока. C>Ну вот как его сделать-то?
Создаёте новый класс class mystringbuf : public std::streambuf. Внутрь засовываете члены-данные и переопределяете необходимые виртуальные функции. Потом:
Можно для удобства завести myistream/myostream, содержащих mystringbuf внутри. Именно так устроены строковые и файловые потоки. Экономия — одна строчка на поток.
MOP>>У Страуструпа расписано немного подробнее, чем в Стандарте. Этого достаточно. Можете также посмотреть реализацию строковых и файловых буферов (или сторонние реализации для gzip и т.п.). C>Ага. Посмотрел. Мозг выпал.
C>>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов.
Оверхед будет из-за внутренней строки. Возьмите stringbuf, выбросьте внутреннюю строку, засуньте data внутрь — и будет то, что надо.
C>>>Это МИНИМАЛЬНЫЙ интерфейс. Если меня он удовлетворяет (к примеру, если у меня устройство один фиг медленное или я пишу всего пару байт), то мне больше ничего не надо. Я так же могу переопределить метод, который пишет массив байт — и будет всё ОК. Я бы сделал фундаментальным именно метод, который пишет массив байт, но это мелочи жизни уже. MOP>>Принцип C++ — zero overhead. Вы не платите за возможности, которые не используете. А если платите — то минимальную цену. Дёргать виртуальный метод на каждую операцию — слишком высокая цена для C++ (ведь можно дешевле). C>Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати.
Ну так в C++ на все потоки одна реализация (sstream и fstream отличаются только косметически).
MOP>>Это ООП наизнанку. Паттерн «стратегия». C>Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию).
Один виртуальный вызов на операцию — уже дорого. В вышеприведённых примерах возможно не будет ни одного виртуального вызова.
Здравствуйте, gegMOPO4, Вы писали:
MOP>Можно для удобства завести myistream/myostream, содержащих mystringbuf внутри. Именно так устроены строковые и файловые потоки. Экономия — одна строчка на поток.
basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать.
C>>>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов. MOP>А можна и готовое использовать. MOP>
MOP>Оверхед будет из-за внутренней строки. Возьмите stringbuf, выбросьте внутреннюю строку, засуньте data внутрь — и будет то, что надо.
Не пойдёт, хотя бы из-за семантики pubsetbuf. Её реализаторы имеют право реализовать её вот так:
(кто там что про виртуальные вызовы, кстати, говорил?)
C>>Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати. MOP>Ну так в C++ на все потоки одна реализация (sstream и fstream отличаются только косметически).
А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае.
MOP>>>Это ООП наизнанку. Паттерн «стратегия». C>>Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию). MOP>Один виртуальный вызов на операцию — уже дорого. В вышеприведённых примерах возможно не будет ни одного виртуального вызова.
В вышеприведённом примере их как минимум 4 штуки только ДЛЯ ИНИЦИАЛИЗАЦИИ. Далее для каждой операции будет один-два виртуальных вызова + промежуточный слой + проверка локали.
Здравствуйте, Cyberax, Вы писали:
C>Ищё IO-библиотеку, построенную на виртуальных классах потоков.
C>Т.е. классический input_stream, от которого наследуется file_input_stream, с возможностью их передать в input_stream_formatter для форматированного вывода и т.п. В общем, чтоб было как в Java
C>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код.
Здравствуйте, night beast, Вы писали:
C>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код. NB>QT::QIODevice не подходит?
Тоже тяжеловесное и кривое.
Пока велосипедирую. Получается что-то вроде:
class input_stream
{
public:
virtual ~input_stream() {};
virtual void read(void *data, size_t bytes)=0;
};
class buf_input_stream : public input_stream
{
typedef std::vector<unsigned char> buf_t;
buf_t buffer;
buf_t::const_iterator pos;
public:
...
virtual void read(void *data, size_t bytes)
{
if (buffer.end()-pos < bytes)
throw std::out_of_range("Premature end of buffer");
std::copy(pos, pos+bytes, static_cast<char*>(data));
pos += bytes;
}
};
И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам.
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, night beast, Вы писали:
C>>>Boost'овое решение активно не нравится из-за отсутствия виртуальности — мне надо классы, использующие эти потоки, вынести в библиотечный код. NB>>QT::QIODevice не подходит? C>Тоже тяжеловесное и кривое.
есть такое дело.
C>Пока велосипедирую. Получается что-то вроде: C>И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам.
Здравствуйте, night beast, Вы писали:
C>>Пока велосипедирую. Получается что-то вроде: C>>И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам. NB>преобразовывать к stringstream?
Думаю насчёт тонкой обёртки в виде реализации istream/ostream. Оверхеда не избежать, но большая часть моего собственного кода легко переделывается на мои потоки. Я туда уже и форматированный вывод даже добавил, только сделаный не криво (как в стандартной библиотеке).
Здравствуйте, Cyberax, Вы писали: C>Здравствуйте, gegMOPO4, Вы писали: MOP>>Можно для удобства завести myistream/myostream, содержащих mystringbuf внутри. Именно так устроены строковые и файловые потоки. Экономия — одна строчка на поток. C>basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать.
Это же библиотечная реализация, там большая часть — комментарии, тайпдефы и прочие пляски, ненужные конкретному типу. basic_stringstream же тривиален, содержит только конструктор и прокси-методы.
C>>>>>Если что, мне надо потоки, которые можно создать полностью на стеке на основе 5-8 байтных статических буфферов. MOP>>А можна и готовое использовать. MOP>>
MOP>>Оверхед будет из-за внутренней строки. Возьмите stringbuf, выбросьте внутреннюю строку, засуньте data внутрь — и будет то, что надо. C>Не пойдёт, хотя бы из-за семантики pubsetbuf. Её реализаторы имеют право реализовать её вот так: C>
C>(кто там что про виртуальные вызовы, кстати, говорил?)
Это абстрактный basic_streambuf, а то — stringbuf.
C>>>Дешевле можно, но только если весь клиентский код работает с конкретной реализацией потоков. Иначе в любом случае нужен где-то виртуальный вызов, и он есть, кстати. MOP>>Ну так в C++ на все потоки одна реализация (sstream и fstream отличаются только косметически). C>А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае.
Но не для каждой операции В/В.
MOP>>>>Это ООП наизнанку. Паттерн «стратегия». C>>>Это не ООП наизнанку, это полный идиотизм дизайнеров. Можно было сделать намного проще и удобнее, с тем же оверхедом (один виртуальный вызов на операцию). MOP>>Один виртуальный вызов на операцию — уже дорого. В вышеприведённых примерах возможно не будет ни одного виртуального вызова. C>В вышеприведённом примере их как минимум 4 штуки только ДЛЯ ИНИЦИАЛИЗАЦИИ. Далее для каждой операции будет один-два виртуальных вызова + промежуточный слой + проверка локали.
Инициализация не считается (к тому же при инициализации виртуальных вызовов может и не быть — мы работаем с конкретными классами). А вот весь В/В внутри функции, куда передали поток, будет в буфер, без виртуальных вызовов. Может быть 1-2 вызова будет в самом конце (да и их можно избежать, если взять буфер с запасом).
Ну вот попробуйте, напишите тест и залогируйте виртуальные функции.
Здравствуйте, Cyberax, Вы писали:
C>>>Пока велосипедирую. Получается что-то вроде: C>>>И манипуляторы к нему. Сейчас думаю как менее криво это пришпилить к стандартным потокам. NB>>преобразовывать к stringstream? C>Думаю насчёт тонкой обёртки в виде реализации istream/ostream. Оверхеда не избежать, но большая часть моего собственного кода легко переделывается на мои потоки. Я туда уже и форматированный вывод даже добавил, только сделаный не криво (как в стандартной библиотеке).
посмотри еще google::protobuf::io.
хотя свой велосипед наверно тоже нормальное решение.
Здравствуйте, gegMOPO4, Вы писали:
C>>basic_stringbuf вылезает примерно в 100 строк!! Не считая ещё прилагающихся к нему basic_stringstream. Не буду я такой ублюдочный интерфейс даже трогать. MOP>Это же библиотечная реализация, там большая часть — комментарии, тайпдефы и прочие пляски, ненужные конкретному типу. basic_stringstream же тривиален, содержит только конструктор и прокси-методы.
Ну приведи простейшую реализацию.
C>>(кто там что про виртуальные вызовы, кстати, говорил?) MOP>Это абстрактный basic_streambuf, а то — stringbuf.
Стандартом это не гарантируется.
C>>А stringbuf — виртуальный. Так что никуда не деться, виртуальные вызовы будут в любом случае. MOP>Но не для каждой операции В/В.
Для КАЖДОЙ операции.
Вызов read() у istream выливается в:
Т.е. в STL не просто одно, а целых ДВА непрямых вызова — как минимум. Сначала непрямой вызов rdbuf(), потом виртуальный вызов xsgetn(). Это ещё не считая проверки всяких failbit и прочей гадости.
И это на КАЖДЫЙ ввод/вывод.
C>>В вышеприведённом примере их как минимум 4 штуки только ДЛЯ ИНИЦИАЛИЗАЦИИ. Далее для каждой операции будет один-два виртуальных вызова + промежуточный слой + проверка локали. MOP>Инициализация не считается (к тому же при инициализации виртуальных вызовов может и не быть — мы работаем с конкретными классами).
Ещё как считается.
MOP>А вот весь В/В внутри функции, куда передали поток, будет в буфер, без виртуальных вызовов. Может быть 1-2 вызова будет в самом конце (да и их можно избежать, если взять буфер с запасом). MOP>Ну вот попробуйте, напишите тест и залогируйте виртуальные функции.
Я уже протрассировал все вызовы. Мой код примерно в 20 раз быстрее на микротестах.