Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: class string, read buffer  (Прочитано 25822 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Mayor
Специалист

ru
Offline Offline

« : 25-07-2009 14:44 » 

class string, read buffer

какие есть методики чтения строки заранее неизвестной длинны из файла?
как это реализовано в std::string?

Записан

1n c0de we trust
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 26-07-2009 16:05 » 

А при чём тут std::string? string - обычный контейнер, и что-либо читать из файла он не умеет.
Записан
Mayor
Специалист

ru
Offline Offline

« Ответ #2 : 26-07-2009 17:19 » 

А при чём тут std::string? string - обычный контейнер, и что-либо читать из файла он не умеет.

std::string это класс на нем определен оператор >>(ifstream& , string)

меня интересуют примеры управления размером буфера при чтении из файла и реализация возможности lazy копирования из буфера
Записан

1n c0de we trust
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 26-07-2009 17:41 » 

Mayor, стринг сам разбирается, сколько выделить памяти под строку. Для этого он и сушествует. Иначе пользуйся нуль терминальной строкой и сам заботься об объеме онной.
Такие задачки легко выясняются на примере в течении 5 минут. Или курением мануалов также в течении 5 минут.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mayor
Специалист

ru
Offline Offline

« Ответ #4 : 26-07-2009 17:49 » 

Mayor, стринг сам разбирается, сколько выделить памяти под строку. Для этого он и сушествует.

снова повторюсь, да знаю что лучше использовать в таких( да и практически в любых) случаях string, но я тренируюсь, вопрос в том как прилизится к идеалу типа std без долгого копания в их исходниках, или хотябы где описаны эти методики ( только где нить страниц на 3-15, а не книжками по 500-800 стр)
Записан

1n c0de we trust
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 26-07-2009 18:30 » 

А ну понятно, нужен STL для чайников. Как говорили в одном фильме "Взлет и посадка"

Если все таки более серьезный подход. То Леен Аммерааль "STL для программистов С++" Там правда 240 страниц. Но расписывается полностью вся работа с библиотекой с примерами.
« Последнее редактирование: 26-07-2009 18:52 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 26-07-2009 18:53 » 

std::string это класс на нем определен оператор >>(ifstream& , string)
Если ты обратишь внимание на 1й аргумент оператора, то поймёшь, что, вообще говоря, он является частью интерфейса класса ifstream. Что он там вытворяет с std::string, никак не касается самого string (точнее, касается ровно в той же степени, как и любой другой клиентский код, использующий string для своих нужд). Поэтому, повторюсь, в string чтение из файла никак не реализовано. Оно реализовано в ifstream
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #7 : 27-07-2009 04:09 » 

выстрел в бошку
Записан

Странно всё это....
Mayor
Специалист

ru
Offline Offline

« Ответ #8 : 27-07-2009 11:10 » 

Если ты обратишь внимание на 1й аргумент оператора, то поймёшь, что, вообще говоря, он является частью интерфейса класса ifstream. Что он там вытворяет с std::string, никак не касается самого string (точнее, касается ровно в той же степени, как и любой другой клиентский код, использующий string для своих нужд). Поэтому, повторюсь, в string чтение из файла никак не реализовано. Оно реализовано в ifstream

оператор берет 2м параметром string, значит он как-то использует его методы при чтении из файла, если он их использует после определения длины строки и с полным копированием данных из буфера значит мне нужен другой пример:
чтения строки заранее неизвестной длинны из файла без копирования полученных данных
те организация буфера позволяющего использовать указатели на него и lazy копирование при попытке изменения содержимого буфера

Записан

1n c0de we trust
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 27-07-2009 11:24 » 

Mayor,

находишь в файле самый первый ноль. Это предположительная длина строки+1. Дальше - делай что хочешь, стандарт для строки ты обеспечил
Записан

Mayor
Специалист

ru
Offline Offline

« Ответ #10 : 27-07-2009 12:41 » 

находишь в файле самый первый ноль. Это предположительная длина строки+1. Дальше - делай что хочешь, стандарт для строки ты обеспечил

я думаю конец строки может быть isspace etc, тогда уже про сразу все из файла скопировать в буфер, а потом зная конец перенести это в структуру строки
Записан

1n c0de we trust
Sla
Модератор

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 27-07-2009 13:03 » 

Mayor, ты не путаешь isspace с eol?
тогда
eol - что это такое?
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #12 : 28-07-2009 05:25 » 

http://www.cplusplus.com/reference/string/getline/
Записан

Странно всё это....
Mayor
Специалист

ru
Offline Offline

« Ответ #13 : 28-07-2009 13:37 » 


мне нужен низкоуровневый алгоритм, который считывает байты из потока только 1 раз и не производит никуда их копирования после считывания. тем не менее, автоматически происходит их разделение на строки
копирование содержимого строк допускается, если приходится к примеру добавить некоторое количество символов в строку.
те :
Код:
custom_string s;
vector<custom_string> v;
while(cin>>s) v.pushback(s);
при обычной реализации, которая приходит мне в голову:
1 берется "безразмерный буфер" в который считывает файл до появления терминатора ( \000, space, \n - в принципе неважно )
2 в объекте s создается ссылка на кучу размером полученной строки
3 копируется туда содержимое буфера размером равным длине строки
4 на векторе создается безымяный индексированый объект того же типа
5 в объекте создается буфер куда копируется содержимое буфера s

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

custom_string s;
cin>>s;
s.insert(3,"lalala"); // здесь допускается перенести данных строки в другой буфер
custom_string s1=s; //здесь должно происходить только копирование указателя на данные
Записан

1n c0de we trust
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #14 : 29-07-2009 03:21 » 

берём файл открытый в бинарном режиме
берём std::string и делаем += по байтику пока не найдём символ перевода строки
тесли волнуют проблемы частой реалокации и так далее
берём как промежуточный буфер deque с при крикрученным boost::pool делаем туда push_back пока не встретим интересующий нас символ, как встретили содержимое копируем в строку

делов на пять минут, вопрос выеденного яйца не стоит, если не начинать думать о реалокациях, двойном копировани и производительности
Записан

Странно всё это....
Mayor
Специалист

ru
Offline Offline

« Ответ #15 : 29-07-2009 11:09 » 

делов на пять минут, вопрос выеденного яйца не стоит, если не начинать думать о реалокациях, двойном копировани и производительности

+= может сделать куеву тучу релокаций, либо чтение строки пойдет из 200 буферов

меня именно интересует ( в плане тренировки), узкоспециализированый класс, который будет производительнее string, за счет заранее изветного % соотношения количества вызовов его методов ( чтений и релокаций будет много больше, чем записей)
Записан

1n c0de we trust
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 29-07-2009 11:28 » 

Mayor, += может делать релокации, а может не делать. Если reserve сделаешь достаточный. А ты как хотел, сразу угадать нужный размер буфера? Ну так тебе сказали, бери deque тогда - он будет блоками релокации делать, а не всё сразу в другой буфер перемещать.
Записан
Mayor
Специалист

ru
Offline Offline

« Ответ #17 : 05-08-2009 17:15 » 

вроде разобрался как сделать копирование объектов string без релокации содержимого: вместо указателя на данные в каждой строке создается указатель на объект, который хранит счетчик строк ссылающихся на него, при удалении строки счетчик декрементируется, когда удаляется последняя строка ссылающаяся на аллокатор, он удаляется вслед за ней

основная проблемма - это перехватить попытку записи в строку, тк при этом следует  создать новый объект-аллокатор для изменяемой строки - я это решил на примере оператора[] :
фишка в том, что этот оператор для не константных строк возвращает не ссылку на символ, а объект - который ведет себя по разному: в случае использования как rvalue - возвращает символ, а когда он поставлен в lvalue, то через перезагрузку оператора = копирует содержимое строки в новый объект-аллокатор (если на предыдущий ссылается больше 1 строки), а потом заменяет индексированый символ в строке на новый
Код:
// NB g++ bug 6257
#include <iostream>
using std::cout;
using std::endl;
using std::cin;

class string {
struct allocator;
struct delimiter; // разделяет опрерации с [] на чтение и запись
struct error {};
allocator* pa; //единые данные для многих одинаковых строк
public:
string(const char* pcc="");
string(const string& s);
~string();
string& operator=(const string& s);
char operator[](int i) const;
delimiter operator[](int i);
int size() const;
};
struct string::allocator {
int sz;
char* pc;
size_t n;
allocator(const char* pcc){
n=1;
sz=strlen(pcc);
pc=new char [sz+1];
strcpy(pc,pcc);
}
~allocator() { delete[] pc; }
void check(int i) { if (i<0 || i>=sz) throw error();}
allocator* copy() { // on write
if(n==1) return this;
allocator* a=new allocator(pc);
n--;
return a;
}
private:
allocator(const allocator&);
allocator& operator=(const allocator&);
};
struct string::delimiter{
string& s;
int i;
delimiter(string& ss,int pos): s(ss),i(pos) {}
operator char() const  { /*
    do not use return s[i] (infine recurse )
    this proc called by non const string[], in place
    requred rvalue:
    string s="aaa";
    cout<<s[1]; // cout<<s.operator[](1).operator_char()
    const string ss="aaa";
    cout<<ss[1]; // cout<<s.operator[](1) const
    */
return s.pa->pc[i];

void operator=(char c) {
/* this called in place where string[i]
* requred as lvalue
* string s="aaaa";
* s[1]='b';
*/
s.pa=s.pa->copy();
s.pa->pc[i]=c;
}
private:
//delimiter(const delimiter&);
//delimiter& operator=(const delimiter&);
};

string::string(const char* pcc){ pa=new allocator(pcc);}
string::~string(){ if(--pa->n==0) delete pa; }
string::string(const string& s){ s.pa->n++; pa=s.pa; }
string& string::operator=(const string& s){
s.pa->n++; // должна быть первой, как защита от самоприсвоения
if(--pa->n==0) delete pa;
pa=s.pa;
return *this;
}
int string::size() const { return pa->sz; }
char string::operator[](int i) const{ pa->check(i); return pa->pc[i]; }
string::delimiter string::operator[](int i){
pa->check(i);
return delimiter(*this,i);
}


void print(const string& s) {
int e=s.size();
for(int i=0;i<e;i++) cout<<s[i];
cout<<endl;
}

void print1(string& s) {
int e=s.size();
for(int i=0;i<e;i++) cout<<s[i];
cout<<endl;
}
int main() {
string s5;
string s("lalalal");
string s1="hehehe";
string s2=s1;
string s3="ulalala";
s="lambda";
s3=s3;
print(s2);
print(s3);
s2[1]='2';
//s3[4]=s2[2];
char c=s2[2];
s3[3]=c;
print(s2);
print(s3);
}
перезагрузка оператора >> читающего строку из ifstream, вроде не должна представлять сложностей
единственное что не понял, как заставить компилироваться выражение типа:
s3[4]=s2[2];
без использования:
char c=s2[2];
s3[3]=c;
Записан

1n c0de we trust
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 05-08-2009 17:55 » 

Copy-on-write, значит, придумал Улыбаюсь Если бы читал, скажем, Саттера, или изучал, как работает MFC, то всё придумалось бы намного раньше.
Насчёт оператора, небольшая подсказка от stl:
     reference operator[] ( size_type n );
const_reference operator[] ( size_type n ) const;
только я бы не поручился, что в качестве rvalue будет использован const reference: собственно, какого значения будет требовать выражение (вызов функции или оператор) - такое и должно использоваться. Но идея с временным объектом мне нравится ещё меньше.
« Последнее редактирование: 05-08-2009 18:06 от Вад » Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #19 : 06-08-2009 03:19 » 

осталось придумать конкатенацию Улыбаюсь строк с одной реалокацией Улыбаюсь, она конечно придумана уже, но это понятное дело не интересно
s1 = s1 + s2 + s3 + s4 + s5; // одна реалокация Улыбаюсь
еще не забываем про оптимизацию для маленьких строк
Кстати в твоём решении я бы просто завёл умный указатель а не реализовывал бы свой.
Записан

Странно всё это....
Mayor
Специалист

ru
Offline Offline

« Ответ #20 : 06-08-2009 16:03 » 

reference operator[] ( size_type n );
const_reference operator[] ( size_type n ) const;

в данном случае независимо от контекста вызова:
первая функция будет вызываться для любых объектов, вторая для константных
скорее всего в const_ref не определен оператор= - и скорее всего и даже независимо от этого он выдаст сбой при использовании в качестве lvalue

я думаю, в этом примере просто приводится заглушка для работы с const объектами, а вся контекстно зависимая логика ( l\rvalue ) будет реализована внутри reference



осталось придумать конкатенацию Улыбаюсь строк с одной реалокацией Улыбаюсь, она конечно придумана уже, но это понятное дело не интересно
s1 = s1 + s2 + s3 + s4 + s5; // одна реалокация Улыбаюсь
еще не забываем про оптимизацию для маленьких строк
Кстати в твоём решении я бы просто завёл умный указатель а не реализовывал бы свой.


придумать то придумал, но боюсь реализовывать:
оператор+(с1,с2) выносится в аллокатор, в котором указатель pc заменен на односвязный список, в концу которого добавляется начало с2 и все узлы с2 инкрементируются
+ приведенная тобой строка ваще не потребует релокации
- придется переносить часть логики string::operator[] в аллокатор, просто не могу просчитать логику работы при удалении строки, ссылающейся на такой аллокатор, имхо такая задачка пока мне рановата

в плане оптимизации маленьких строк реализовал операторы:
Код:
string& string::operator+=(char c) { pa->add(c); return *this; }
bool string::is_space(char c) { return space_separator.check(c); }
istream& operator>>(istream& ist,string& s){
char c=0;
s="";
while(ist.get(c)) if (!string::is_space(c)) {
ist.putback(c);
break ;
}
while(ist.get(c) && !string::is_space(c) ) {
std::cout<<c<<std::endl;
s+=c;
}


return ist;
}
#ifndef string_separatorSS
#define string_separatorSS
struct separator{
static const int max=256;
char *pc;
separator(const char* pcc=" \t\n\r") {
pc=new char[max];
for(int i=0;i<max;i++) pc[i]=0;
while(*pcc) pc[*pcc++]=1;
}
~separator() { delete[] pc; }
bool check(char c) const { return pc[c]; }
};
#endif
#ifndef string_allocatorSS
#define string_allocatorSS
struct string::allocator {
int sz;
int free;
char* pc;
size_t n;
const static int bufer_reserv=10;
allocator(const char* pcc){
n=1;
sz=strlen(pcc);
pc=new char [sz+1];
free=1;
strcpy(pc,pcc);
}
~allocator() { delete[] pc; }
void check(int i) { if (i<0 || i>=sz) throw error();}
allocator* copy() { // on write
if(n==1) return this;
allocator* a=new allocator(pc);
n--;
return a;
}
void add(char c) {
if(!free) {
char* dest=new char[sz+bufer_reserv];
memcpy(dest,pc,sz);
delete[] pc;
pc=dest;
free=bufer_reserv;
}
pc[sz++]=c;
free--;
}


private:
allocator(const allocator&);
allocator& operator=(const allocator&);
};
#endif
тк не научился использовать placement object на вершине кучи, то приходится просто снижать число релокаций при чтении с буфера в н раз ценой расхода памяти
и пока еще не понял как использовать умный указатель, и ваще зачем он тут нужен?
« Последнее редактирование: 06-08-2009 17:24 от Sel » Записан

1n c0de we trust
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #21 : 07-08-2009 05:16 » 

реализация через список блоков, называется std::rope, а не string
попробуй подумать, как можно реализовать оператор + без реалокаций(миним реалокаций) для строки хранящей непрерывную последовательность байт.
http://rsdn.ru/article/cpp/smartptr.xml

Код:
   int * i = new int(12);
   int * j = new(i) int(7);   // placement new
Записан

Странно всё это....
Mayor
Специалист

ru
Offline Offline

« Ответ #22 : 09-08-2009 09:11 » 

реализация через список блоков, называется std::rope, а не string
попробуй подумать, как можно реализовать оператор + без реалокаций(миним реалокаций) для строки хранящей непрерывную последовательность байт.
единственное, что приходит в голову: нарушить правило по созданию временного объекта для оператора+:
string& string::operator(string& s1,const string& s2) ; // но тогда уже практически получается оператор +=



http://rsdn.ru/article/cpp/smartptr.xml
Код:
   int * i = new int(12);
   int * j = new(i) int(7);   // placement new

хм, прочитал походу мне еще рано использовать умные указатели в реальных боевых приложениях, я думаю стоит к ним вернуться, когда появится время и возможность на изучение дизайна с++ приложений\шаблонов проектирования
Записан

1n c0de we trust
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #23 : 10-08-2009 04:52 » 

единственное, что приходит в голову: нарушить правило по созданию временного объекта для оператора+:
string& string::operator(string& s1,const string& s2) ; // но тогда уже практически получается оператор +=

оператор + может возвращать не строку, а нечно иное

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

спорный вопрос.
Записан

Странно всё это....
Mayor
Специалист

ru
Offline Offline

« Ответ #24 : 10-08-2009 10:12 » 

оператор + может возвращать не строку, а нечно иное
ты начинаешь говорить загадками Улыбаюсь , попробую угадать: operator+ может тоже вернуть временный  объект, для которого в строке переопределен оператор= и в котором переопределен оператор+ ...

но как только появляются выражения типа a+b+c+d+.... сразу же  начнется чехорда с auto_ptr<string>, а   дальше как следствие единственный выход через патерн "алокация есть инициализация"

статейка то прикольная, но при моем уровне нужно либо изобретать велосипед самому с неопределенным  успехом, либо методично прокачать объектную часть с++ вместе с stl, а потом в контексте изучения дизайна с++ приложений пройти УУ

хотя в принципе, безо всякой теоретической основы, мне удалось самому реализовать патерн copy on write, естественно получилось криво, но оно работало\ет, будет ли также со смартами?

по любому, спасибо за то, что указал в каком направлении после с++, читать теорию дальше

спорный вопрос.

ну не знаю, насколько мне извстно из статей по управлению проектами, джуниорам не рекомендуют сразу давать прибегать к smart pointers
Записан

1n c0de we trust
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #25 : 10-08-2009 11:05 » 

оператор + может возвращать не строку, а нечно иное
ты начинаешь говорить загадками Улыбаюсь , попробую угадать: operator+ может тоже вернуть временный  объект, для которого в строке переопределен оператор= и в котором переопределен оператор+ ...

Ты можешь вернуть некий объект StrConcatenator цель которого собирать информацию о строках (длина и адрес)
Далее при попытке присвоить этот некий объект объекту строка внешний оператор вытасикивает из объекта собранную информацию делает 1 реалокацию и приступает к размещению строк во вновь выделенную память.
Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines