Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Программирование на Visual С++" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
C++ для всех
Информационный Канал Subscribe.Ru |
C++ для всех. Выпуск 10 Исключения. Спецификация исключений |
Здравствуйте, уважаемые подписчики
Сегодня я попробую в доступной форме описать механизм исключений, которые являются одной из ключевых фигур в языке С++.
Итак, начнем... При разработке программ могут возникать ситуации, которые требуют обязательной реакции программиста. Без использования исключений единственным способом является установка какого-либо флага, указывающего, например об ошибке. Но главная проблема это то, что данный флаг может быть просто проигнорирован. И здесь на сцену выходят исключения - их проигнорировать нельзя. Любое необработанное исключение приводит к вызову функции terminate(), которая немедленно завершает выполнение программы без вызова деструкторов для локальных и статических объектов. Генерируется исключение с помощью ключевого слова throw. Напишем пример генерации исключения:
int main() { throw; std::cerr << "after throw\n"; return 0; }
После выполнения программы мы ничего не увидим на экране, т.к. необработанное исключение привело к вызову функции terminate().
Исключение может иметь спецификацию, и соответственно, мы можем поймать (другого слова что-то придумать не могу) и обработать исключение на основании данной спецификации. Необработанное исключение обрабатывается как unexpected(), что приводит к вызову функции terminate(). Мы можем переопределить стандартные функции с помощью set_unexpected(typedef void(*unexp_func)()) и set_terminate(typedef void(*term_func)()) задать свою функцию, которая будет вызываться вместо unexpected(), но запретить завершение на данном этапе уже не получится, да и не имеет смысла:
void my_terminate() { std::cerr << "my_terminate!\n"; } int main() { std::set_terminate(my_terminate); throw 10; }
На экране увидим результат работы функции my_terminate():
my_terminate!
Теперь разберемся, как ловить и обрабатывать исключения. Для обработки исключений код, который может генерировать исключения, должен помещаться в блок try...catch. Рассмотрим пару примеров:
а) int main() { char *buf; try{ buf = new char[1024*1024*1024*10]; //10GB ... } catch(std::bad_alloc){ std::cerr << "std::bad_alloc\n"; } delete [] buf; return 0; } б) int main() { if(FILE *f = fopen("c:/xxx.dat","w")){ try{ //работа с файлом } catch(...){ fclose(f); } fclose(f); } return 0; }
В примере а) показан типичный пример обработки исключения, которое генерится при невозможности выделить затребованный блок памяти (короче - нехватка памяти). В примере б) показан способ очистки выделенных ресурсов после генерирования исключений. Смотрим на параметр, заключенный в скобки catch(): в скобках указывается спецификатор исключения или троеточие, которое подразумевает любое исключение, т.е. возможно писать так:
int main() { try(){ func(); } catch(const char *str){ ... } catch(const std::string&){ ... } catch(int){ ... } catch(...){ ... } return 0; }
В вышеприведенном примере если не параметр исключения не совпадет ни с одним из типизированных обработчиков catch, исключение будет обработано в последнем блоке catch(...).
B случае, когда пойманное исключение не может быть обработано в текущем блоке (например, мы ничего не знаем о данном исключении или обработана только часть критической ситуации) можно или передать исключение в чистом виде дальше или сгенерировать новое исключение с другим параметром, например:
а) Передача исключения дальше void func(int v){ if(!v) throw "const char* exception!"; else throw v; } int main() { try{ try{ func(0); } catch(int){ //обработаем } catch(...){ //не знаем, что делать - передадим дальше throw; } } catch(const char *str){ std::cerr << str << '\n'; } return 0; } б) Генерация нового исключения ... int main() { try{ try{ func(10); } catch(int v){ //обработаем и сгенерим новое исключение static char buf[32]; sprintf(buf,"unexpected value %d!",v); throw buf; } catch(...){ //не знаем, что делать - передадим дальше throw; } } catch(const char *str){ std::cerr << str << '\n'; } return 0; }
На экране после выполнения увидим:
а) const char* exception! б) unexpected value 10!
Теперь разберемся какие параметры можно передавать ключевому слову throw. Ответ такой - любые. Мы можем определить любой тип и передавать объекты этого типа в качестве параметра исключения, например:
struct SException{ int v; SException(int v_=10):v(v_){} void print(){ if(v==0) std::cerr << "description of exception number 0\n"; else if(v==1) std::cerr << "description of exception number 1\n"; else std::cerr << "undefined exception number\n"; } }; SException g_exc; void func( int v ){ try{ if(v==0) throw SException(v); else{ g_exc.v = v; throw &g_exc; } } catch(SException exc){ std::cerr << "catch(SException exc)\n"; exc.print(); } catch(SException *pexc){ std::cerr << "catch(SException *pexc)\n"; pexc->print(); } } int main() { func(0); func(1); return 0; }
Спецификация исключений
Теперь рассмотрим спецификацию исключений касательно функций. Каждая функция может дополняться спецификатором исключений, который говорит, что функция может генерить только указанные исключения или вообще не возбуждает исключений при наличии ключевого слова throw() без параметров. Например:
void func() throw(int) - данная функция может возбуждать исключения типа int void func() throw(const char*) - данная функция может возбуждать исключения типа const char* void func() throw(int,const char*) - только int или const char* void func() throw(T1,T2) - только T1 или T2 (или производных от них) void func() throw() - данная функция не возбуждает исключений
Данная спецификация призвана дать определенные гарантии, т.е. программист может быть уверен, что возможны исключения только указанного типа. Согласно стандарта любые исключения, которые не входят в объявленную спецификацию, будут интерпретироваться в unexpected() и приведут к вызову функции terminate(). Однако это только в теории, на практике все зависит от компилятора, и лично я не встречал компилятора, который бы выполнял это требование. Посмотрите на следующий пример:
void func() throw() { throw 10; } int main() { try{ func(); } catch(int){ std::cerr << "throw(int)\n"; } catch(...){ std::cerr << "unexpected\n"; } return 0; }
Согласно стандарта я должен ожидать, что попаду в блок catch(...) и на экране увижу unexpected, но, при компиляции на VC7.1 и выполнении я попадаю в блок catch(int), gcc 3.2.1 вообще вызывает abort() без всяких разговоров... Поэтому, пока спецификация - это только "украшение", которое носит только информативный и предписывающий характер, хотя возможно, что в дальнейшем ситуация и изменится.
Пожалуй, на сегодня теории хватит. Более подробно о применении исключений мы поговорим в следующем выпуске.
Практическое занятие
В прошлом выпуске мы начали писать класс обработчик конфигурационных файлов, сегодня мы его закончим.
Для начала изменим пару строк в написанном классе TTree - эти изменения нужны для случая, когда элемент TTree является указателем на массив объектов:
Ищем:
~Item(){ ... if(ttree->autoDelete()) delete data; ... }
заменяем на
~Item(){ ... if(ttree->autoDelete()) ttree->deleteData(data); ... }
После этого добавим функцию-член к классу TTree:
template<class T> class TTree { ... protected: virtual void deleteData(T *t){ delete t; } ... };
С исправлениями класса TTree закончили. Теперь напишем класс, который непосредственно работает с параметрами конфигурационного файла. Сразу скажу, что пример получился несколько великоват для учебных целей, но здесь нет ничего лишнего, а класс довольно полезный. При написании будет использоваться ранее написанный класс списка указателей, который был реализован в седьмом выпуске.
Сначала заголовочный файл:
--saver.h--start------------------------------------------------------------------------------------- #ifndef SAVER_H #define SAVER_H /*************************************************************************** saver.h - description ------------------- copyright : (C) 2003 by Yuri Gordienko email : iqsoft@cg.ukrtel.net ****************************************************************************/ #include "tree.h" #include "ptrlist.h" #include <stdio.h> //первый символ в строке-параметре: 1-node,0-обычный параметр const char* firstNotSpace(char *str); int getline(char **buf,int *n,FILE*); class TSaver : public TTree<char> { struct SNameList{ const char *name; int len; SNameList *next; }; public: enum Type{ nodes, params, any }; TSaver(); TSaver(const TSaver&); ~TSaver(){ clear(); } bool load(const char*); void load(FILE*); bool save(const char*)const; void save(FILE *f)const{ saveparams(f,firstItem(),0); } Item* setParam(const char*,const char*,Item *parent=0); Item* setParam(const char*,bool,Item *parent=0); Item* setParam(const char*,int,Item *parent=0); Item* setParam(const char*,double,Item *parent=0); Item* getParam(const char*,const Item *parent=0)const; Item* getParam(const char*,bool&,bool *ok=0,const Item *parent=0)const; Item* getParam(const char*,int&,bool *ok=0,const Item *parent=0)const; Item* getParam(const char*,double&,bool *ok=0,const Item *parent=0)const; //вернет name=value static const char* getParam(const Item*); bool getParams(TPtrList<const Item>&,const char*,const Item *parent=0,Type tp=params)const; bool getParams(TPtrList<const char>&,const char*,const Item *parent=0,Type tp=params)const; //извлекает и удаляет (только из списка) запись static const Item* extractParam(TPtrList<const Item>&,const char*,Type tp=params); const char* getValue(const char*,const Item *parent=0)const; static const char* getValue(const Item*); static bool getValue(const Item*,bool&); static bool getValue(const Item*,int&); static bool getValue(const Item*,double&); //удаляет или строку параметра или поле-родителя со всеми наследниками bool delParam(const char*,Item *parent=0); void changeParam(Item&,const char*); Item* createNode(const char*,Item *parent=0); static bool isNode(const Item&); //переносим параметр или меняем порядок. Недопустимо переносить родителя детям (вглубь родственной иерархии) //пример moveParam("node1.node2.name","node1"), moveParam("node1.node2.user=","node1") bool moveAfter(const char *from, const char *after); //в отличие от предыдущего вставляет себя в качестве childa(последним). bool moveIn(const char *from, const char *in); const TSaver &operator=(const TSaver&); protected: virtual void deleteData(char *pdata){ delete [] pdata; } Item* getEqualWay(const Item *item,SNameList *&plist)const; void saveparams(FILE *fl, const Item *item, int pos)const; void copy_operator(const Item *pclone,Item *parent); SNameList* getnamelist(const char*)const; }; inline bool TSaver::isNode(const Item &item) { return item.getData()[0]!=0; } inline const char* TSaver::getParam(const Item *item) { return item ? &item->getData()[1] : 0; } inline TSaver::Item* TSaver::setParam(const char *path,bool b,Item *parent) { return setParam(path,b ? "1" : "0",parent); } inline TSaver::Item* TSaver::createNode(const char *path,Item *parent) { return setParam(path,(const char*)0,parent); } inline const char* TSaver::getValue(const char *path,const Item *parent)const { return getValue(getParam(path,parent)); } #endif //SAVER_H --saver.h--end---------------------------------------------------------------------------------------
Теперь реализация:
--saver.cpp--start----------------------------------------------------------------------------------- #include "saver.h" #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stack> const char* firstNotSpace(char *str) { const char *p = str; while(isspace(*p)) ++p; return p; } int getline(char **pbuf,int *n,FILE *f) { const int read_cnt=64; char buf[read_cnt]; int num_read,i; for(int cnt=0;;++cnt){ num_read = fread(buf,1,read_cnt,f); if(num_read<=0) break; for(i=0;i<num_read;++i){ if(!buf[i] || buf[i]=='\n' || buf[i]=='\r'){ int len = read_cnt*cnt+num_read; if(fseek(f,(-1)*len,SEEK_CUR)==0){ //удача len += (i-num_read+2); if(*n<len){ *n = len; *pbuf = (char*)realloc(*pbuf,len); } --len; if(fread(*pbuf,1,len,f)==len){ (*pbuf)[len] = 0; return ++len; } } return -1; } } } return -1; } TSaver::TSaver() :TTree<char>(true) { } TSaver::TSaver(const TSaver &s) :TTree<char>(true) { *this = s; } void TSaver::copy_operator(const Item *pclone,Item *parent) { Item *nitem = 0; const char *pdata; char *p; int len; while(pclone){ pdata = pclone->getData(); len = strlen(&pdata[1])+2; p = new char[len]; memcpy(p,pdata,len); nitem = (!nitem && parent) ? new Item(*parent,p) : new Item(*this,nitem,p); copy_operator(pclone->firstChild(),nitem); pclone = pclone->next(); } } const TSaver& TSaver::operator=(const TSaver &s) { if(this!=&s){ clear(); copy_operator(s.firstItem(),0); } return *this; } bool TSaver::load(const char *fname) { FILE *f; if(f = fopen(fname,"rb")){ load(f); fclose(f); } return f!=0; } void TSaver::load(FILE *f) { std::stack<Item*> stack_p; char *buf = 0; int count = 0; size_t len; Item *item; stack_p.push(0); const char *pdata,*p; while((len=getline(&buf,&count,f))!=-1){ buf[len-2] = 0;//забъем символ перевода строки 0 pdata = p = firstNotSpace(buf); if(*p=='<'){ if(p[1]){ if(const char *cpos = strchr(&p[1],'>')){ ++p; if(*p=='/' && p[1] && stack_p.size()>1) stack_p.pop(); else{ len = cpos-p; char *param = new char[len+2]; *param = 1; memcpy(¶m[1],p,len); param[len+1] = 0; if(Item *pitem = stack_p.top()) item = new Item(*pitem,param,true); else item = new Item(*this,lastItem(firstItem()),param); stack_p.push(item); } continue; } } } //добавляем как обыкновенный параметр if(len = strlen(pdata)){ len+=2; char *param = new char[len]; *param = 0; memcpy(¶m[1],pdata,len-1); if(Item *pitem = stack_p.top()) item = new Item(*pitem,param,true); else item = new Item(*this,lastItem(firstItem()),param); } } free(buf); } bool TSaver::save(const char *fname)const { FILE *f = fopen(fname,"wb"); if(f){ save(f); fclose(f); } return f!=0; } TSaver::Item* TSaver::getEqualWay(const Item *item,SNameList *&plist)const { Item *ret = 0; if(item && plist){ const char *pdata; SNameList *pn; while(item){ pdata = item->getData(); if(plist->next){ //ищем только узел if(*pdata && (strncmp(&pdata[1],plist->name,plist->len)==0) && !pdata[plist->len+1]){ pn = plist->next; memcpy(plist,plist->next,sizeof(SNameList)); free(pn); ret = getEqualWay(item->firstChild(),plist); break; } } else if( (*pdata && (plist->name[plist->len-1]!='=') && (strcmp(&pdata[1],plist->name)==0)) || (!*pdata && (strncmp(&pdata[1],plist->name,plist->len)==0)) ){ free(plist); plist = 0; break; } item = item->next(); } if(!ret && item) ret = const_cast<Item*>(item); } return ret; } TSaver::Item* TSaver::setParam(const char *path,const char *param,Item *parent) { Item *last_item = 0; if(path && *path){ if(SNameList *plist = getnamelist(path)){ //разбили на лексемы if(Item *pf = parent ? parent->firstChild() : firstItem()) last_item = getEqualWay(pf,plist); if(!last_item && parent) last_item=parent; if(SNameList *p = plist){ char *pdata; bool is_node; int par_len = param ? strlen(param) : 0; while(p){ //создадим узлы is_node = (p->next || (p->name[p->len-1]!='=')); if(is_node){ pdata = new char[p->len+2]; memcpy(&pdata[1],p->name,p->len); pdata[p->len+1] = 0; }else{ pdata = new char[1+p->len+par_len+1]; memcpy(&pdata[1],p->name,p->len); if(par_len) memcpy(&pdata[1+p->len],param,par_len+1); else pdata[p->len+1] = 0; } *pdata = char(is_node); if(last_item) last_item = new Item(*last_item,pdata,true); else last_item = new Item(*this,lastItem(),pdata); p = plist->next; free(plist); plist = p; } }else changeParam(*last_item,param); } } return last_item; } TSaver::Item* TSaver::setParam(const char *path,int v,Item *parent) { char buf[16]; sprintf(buf,"%d",v); return setParam(path,buf,parent); } TSaver::Item* TSaver::setParam(const char *path,double v,Item *parent) { char buf[64]; sprintf(buf,"%.17f",v); return setParam(path,buf,parent); } TSaver::Item* TSaver::getParam(const char *path,const Item *parent)const { Item *ret = 0; if(SNameList *plist = getnamelist(path)){ //разбили на лексемы if(Item *pf = parent ? parent->firstChild() : firstItem()) ret = getEqualWay(pf,plist); if(plist){ SNameList *p; while(plist){ p=plist->next; free(plist); plist = p; } ret = 0; } } return ret; } bool TSaver::getParams(TPtrList<const Item> &list,const char *path,const Item *parent,Type tp)const { const Item *item; if(path || parent){ if(item = path ? getParam(path,parent) : parent){ item = item->firstChild(); if(!item) return true; } }else item = firstItem(); if(item){ const char *pdata; while(item){ pdata = item->getData(); if(tp==any || (tp==params && !*pdata) || (tp==nodes && *pdata)) list.append(item); item = item->next(); } return true; } return false; } bool TSaver::getParams(TPtrList<const char> &list,const char *path,const Item *parent,Type tp)const { const Item *item; if(path || parent){ if(item = path ? getParam(path,parent) : parent){ item = item->firstChild(); if(!item) return true; } }else item = firstItem(); if(item){ const char *pdata; while(item){ pdata = item->getData(); if(tp==any || (tp==params && !*pdata) || (tp==nodes && *pdata)) list.append(&pdata[1]); item = item->next(); } return true; } return false; } const TSaver::Item* TSaver::extractParam(TPtrList<const Item> &list,const char *name,Type tp) { const Item *ret = 0; if(name){ int len = strlen(name); const char *pdata; for(ret=list.first();ret;ret=list.next()){ pdata = ret->getData(); if(tp==any || (tp==params && !*pdata) || (tp==nodes && *pdata)) if(memcmp(&pdata[1],name,len + (*pdata ? 1 : 0) )==0) break; } if(ret) list.remove(ret); } return ret; } bool TSaver::getValue(const Item *item,bool &v) { if(const char *ch = getValue(item)){ v = (*ch!='0'); return true; } return false; } bool TSaver::getValue(const Item *item,int &v) { if(const char *ch = getValue(item)){ errno = 0; int v1 = strtol(ch, 0, 0); if(!errno){ v = v1; return true; } } return false; } bool TSaver::getValue(const Item *item,double &v) { if(const char *ch = getValue(item)){ errno = 0; double v1 = strtod(ch,0); if(!errno){ v = v1; return true; } } return false; } TSaver::Item* TSaver::getParam(const char *path,bool &v,bool *ok,const Item *parent)const { Item *ret = getParam(path,parent); if(ret){ bool i_ok; if(!ok) ok = &i_ok; *ok = getValue(ret,v); } return ret; } TSaver::Item* TSaver::getParam(const char *path,int &v,bool *ok,const Item *parent)const { Item *ret = getParam(path,parent); if(ret){ bool i_ok; if(!ok) ok = &i_ok; *ok = getValue(ret,v); } return ret; } TSaver::Item* TSaver::getParam(const char *path,double &v,bool *ok,const Item *parent)const { Item *ret = getParam(path,parent); if(ret){ bool i_ok; if(!ok) ok = &i_ok; *ok = getValue(ret,v); } return ret; } void TSaver::saveparams(FILE *fl, const Item *item, int pos)const { if(!item) return; const int buf_size = 64; char buf[buf_size]; char *pstr = buf; if(pos+1>buf_size) pstr = (char*)malloc(pos+1); if(pos) memset(pstr,'\t',pos); pstr[pos] = 0; const char *pdata; while(item){ pdata = item->getData(); if(*pdata++){ //узел if(pos) fprintf(fl,"%s<%s>\n",pstr,pdata); else fprintf(fl,"<%s>\n",pdata); saveparams(fl,item->firstChild(),pos+1); if(pos) fprintf(fl,"%s</%s>\n",pstr,pdata); else fprintf(fl,"</%s>\n",pdata); }else{ if(pos) fprintf(fl,"%s%s\n",pstr,pdata); else fprintf(fl,"%s\n",pdata); } item = item->next(); } if(pstr!=buf) free(pstr); } void TSaver::changeParam(Item &item,const char *par) { char *pdata = item.getData(); char *p; int len = 2; if(par) len+=strlen(par); if(*pdata){ if(!par) return; p = new char[len]; if(par) memcpy(&p[1],par,len-2); }else{ int slen; ++pdata; const char *pe = strchr(pdata,'='); if(pe) slen = pe-pdata; else slen = strlen(pdata); ++slen; p = new char[len+slen]; memcpy(&p[1],pdata,slen); if(!pe) p[slen]='='; if(par) memcpy(&p[1+slen],par,len-2); len+=slen; --pdata; } *p = *pdata; p[len-1] = 0; delete [] pdata; item.setData(p); } //удаляет или строку параметра или поле-родителя со всеми наследниками bool TSaver::delParam(const char *path,Item *parent) { Item *item = getParam(path,parent); bool ret = (item!=0); delete item; return ret; } //переносим параметр или меняем порядок bool TSaver::moveAfter(const char* from, const char *after) { if(Item *pfrom = getParam(from)){ Item *pafter = getParam(after); if(pafter && (pafter!=pfrom)){ //удалим параметр с аналогичным именем, если есть (и возможно) const char *pch = strrchr(from,'.'); if(!pch) pch = from; else ++pch; const char *pdata; int len = strlen(pch); bool is_node = *pch ? !pch[len-1] : true; Item *pfi = firstItem(pfrom); do{ if(pfrom!=pfi){ pdata = pfi->getData(); if(is_node){ if(*pdata && strcmp(&pdata[1],pch)==0) break; }else{ if(!*pdata && strncmp(&pdata[1],pch,len)==0) break; } } }while(pfi=pfi->next()); pfrom->moveItem( *pafter ); delete pfi; return true; } } return false; } //вставляет себя в качестве childa bool TSaver::moveIn(const char *from, const char *to) { if(!from || !to) return false; if(Item *pfrom = getParam(from)){ Item *pto = getParam(to); if(pto==pfrom) return false; if(!pto) pto = setParam(to,0); else{ //удалим параметр с аналогичным именем, если есть const char *pch = strrchr(from,'.'); if(!pch) pch = from; else ++pch; if(Item *fi = getParam(pch,pto)){ if(fi!=pfrom) delete fi; } } if(pto && (pto!=pfrom)){ Item *litem = pto->firstChild(); Item *item = litem ? lastItem( litem ) : 0; if(item) pfrom->moveItem( *item ); else{ item = new Item(*pto,0); pfrom->moveItem( *item ); delete item; } return true; } } return false; } //разбор входящей строки типа node1.node2.name на список указателей TSaver::SNameList* TSaver::getnamelist(const char* str) const { SNameList *ret = 0; if(str && *str && *str!='.'){ const char* fch = strchr(str,'.'); ret = (SNameList*)malloc(sizeof(SNameList)); ret->name = str; if(fch){ ret->len = fch-str; ret->next = getnamelist(++fch); }else{ ret->len = strlen(str); ret->next = 0; } } return ret; } const char* TSaver::getValue(const Item *item) { const char *ret = 0; if(item){ ret = item->getData(); if(!*ret){ //не узел ret = strchr(++ret,'='); if(ret) ++ret; }else ++ret; } return ret; } --saver.cpp--end-------------------------------------------------------------------------------------
Теперь напишем пример, показывающий как этот класс использовать:
int main() { const char *file_ini = "config.ini"; TSaver sv; sv.load(file_ini); //загрузим параметры из файла //создадим пару параметров (или найдем если они уже есть) TSaver::Item *parent = sv.createNode("node1.node2.node3"); char buf[32]; int i; //создадим параметры используя относительный путь (быстро) for(i=0;i<10;++i){ sprintf(buf,"name%d=",i); sv.setParam(buf,i,parent); } //добавим еще параметр используя относительный путь (долго) sv.setParam("node1.node2.node3.value=","undefined"); //добавим еще параметр в новый узел второго уровня sv.setParam("node1.XXXXXXX.value=","undefined"); //удалим ранее созданный параметр через относительный путь (бысто) sv.delParam("name1=",parent); //удалим ранее созданный параметр через абсолютный путь (долго) sv.delParam("node1.node2.node3.name2="); //создадим и удалим узел sv.createNode("xnode"); sv.delParam("xnode"); //создадим и удалим узел по-другому TSaver::Item *pnode = sv.createNode("xnode"); delete pnode; //запишем и получим параметры основных типов через относительный путь parent = sv.createNode("values"); sv.setParam("int_value=",10,parent); sv.setParam("double_value=",10.22,parent); sv.setParam("const char_value=","const char",parent); sv.setParam("bool_value=",true,parent); bool ok; int ival; double dval; const char *pch; bool bval; if(sv.getParam("int_value=",ival,&ok,parent) && ok) std::cerr << "int_value=" << ival << '\n'; if(sv.getParam("double_value=",dval,&ok,parent) && ok) std::cerr << "double_value=" << dval << '\n'; if(pch = sv.getValue("const char_value=",parent)) std::cerr << "const char_value=" << pch << '\n'; if(sv.getParam("bool_value=",bval,&ok,parent) && ok) std::cerr << "bool_value=" << bval << '\n'; //получим и распечатаем имена всех параметров узла std::cerr << "params of node1.node2.node3\n"; TPtrList<const TSaver::Item> elist; sv.getParams(elist,"node1.node2.node3",0,TSaver::params); const TSaver::Item *p; for(p=elist.first();p;p=elist.next()) std::cerr << sv.getParam(p) << '\n'; //получим и распечатаем имена всех узлов данного узла std::cerr << "nodes of node1\n"; elist.clear(); sv.getParams(elist,"node1",0,TSaver::nodes); for(p=elist.first();p;p=elist.next()) std::cerr << sv.getParam(p) << '\n'; //получим и распечатаем имена всех узлов и параметров корня std::cerr << "all of root\n"; elist.clear(); sv.getParams(elist,0,0,TSaver::any); for(p=elist.first();p;p=elist.next()) std::cerr << sv.getParam(p) << '\n'; //создадим два узла и переместим один узел в другой sv.createNode("xxx.first"); sv.createNode("xxx.second"); sv.moveIn("xxx.second","xxx.first"); //создадим три параметра и изменим порядок параметров sv.setParam("param1=","1"); sv.setParam("param2=","2"); sv.setParam("param3=","3"); sv.moveAfter("param1=","param3="); //создадим независимую копию данного объекта и сохраним в другой файл TSaver sv1(sv); sv1.save("config_new.ini"); sv.save(file_ini); return 0; }
Остальное можете посмотреть в декларации класса.
На сегодня все. Пожелания, предложения, вопросы прошу на iqsoft@cg.ukrtel.net
В следующем выпуске - написание безопасного в плане исключений кода
(с) Юрий Гордиенко
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||