tratarea exceptiilor.spatii de nume. i/o

68
Tratarea Exceptiilor.Spatii de nume. I/O Curs 12-13

Upload: thor

Post on 14-Jan-2016

27 views

Category:

Documents


1 download

DESCRIPTION

Tratarea Exceptiilor.Spatii de nume. I/O. Curs 12-13 . Tratarea erorilor. C : int printf ( const char * format, ... ); Return Value: On success , the total number of characters written is returned. On failure , a negative number is returned. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Tratarea Exceptiilor.Spatii de nume. I/O

Tratarea Exceptiilor.Spatii de nume. I/O

Curs 12-13

Page 2: Tratarea Exceptiilor.Spatii de nume. I/O

Tratarea erorilor

• C :– int printf ( const char * format, ... ); – Return Value:

– On success, the total number of characters written is returned.

On failure, a negative number is returned. – Rareori programatorii verifica codul de retur– In cazul in care o fac, codul este o succesiune de if-uri care verifica variatele

posibilitati

– Problema majora – cuplarea – dependenta – gradul in care un modul depinde de un alt modul

Page 3: Tratarea Exceptiilor.Spatii de nume. I/O

Tratarea erorilor in C

1. Valoare de retur care indica o problema

2. Setarea unui flag care sa indice existenta unei erori : errno, perror()– errno – variabila intreaga declarata in <errno.h>, folosita de

numeroase functii pentru a returna coduri de eroare– void perror ( const char * str ) (print error message)– Interpreteaza valoare lui errno si o converteste la un string pe

care il afiseaza pe stderr (de obicei ecran)– perror () trebuie apelata chiar dupa aparitia erorii, altfel poate fi

suprascrisa de alte functii

3. Folosirea setjmp() si longjmp()– setjmp() salveaza o stare normala a programului– In situatii de eroare se apeleaza longjmp() care restaureaza

acea stare buna– NU apeleaza DESTRUCTORII!!! (folosit in C++)

Page 4: Tratarea Exceptiilor.Spatii de nume. I/O

Tratarea erorilor CErrno+perror

#include <stdio.h>#include <errno.h>

int main (){ FILE * pFile; pFile=fopen ("unexist.txt","rb"); if (pFile==NULL){ printf("errno = %d\n", errno); perror ("The following error occurred"); } else fclose (pFile); return 0;}

Cod de retur

char *c = new char[200000000]if ( c == NULL ) cout<<“eroare"; else{ //procesare informatii …

delete c; }

Page 5: Tratarea Exceptiilor.Spatii de nume. I/O

Sabloane GRASP• GRASP – General Responsibility Assignment Patterns (Principles)

• Low coupling – dezvoltarea de module independente

– dependenta scazuta intre module,

– modificari asupra unui modul sa nu determine modificari majore asupra altor module

• High Cohesion

– un modul trebuie sa aiba o multime de responsabilitati relationate

– Utilizarea claselor oera suport pentru coeziunea unui proiect

• Controller

– Delegarea sarcinilor de tratare a evenimentelor din interfata grafica unei clase cu rol de tratare a evenimntelor

• Polimorfism – variatiile comportamentelor pe baza tipurilor de date sunt tratate de tipul de date, folosind apeluri polimorfice

Page 6: Tratarea Exceptiilor.Spatii de nume. I/O

Tratarea erorilor in C

• Codul de tratare a erorilor este puternic cuplat cu codul logicii aplicatiei

• La apelul unei functii care returneaza un cod de eroare, inconjuram codul care face apelul de cod de testare a modului de finalizare a apelului

• NULL si -1 (valori negative) folosite pentru a indica esecul unui apel – trebuie testate imediat dupa apel

• La folosirea setjmp si longjmp exista o puternica cuplare intre codul unde se slaveaza starea normala si codul in care apare eroarea

Page 7: Tratarea Exceptiilor.Spatii de nume. I/O

Abordarea C++

• Tratarea exceptiilor:• Codul de tratare a erorilor este separat de codul care trateaza logica

aplicatiei– Intai scriem codul care dorim sa se execute, apoi separat, se scrie codul

care se ocupa de tratarea situatiilor neprevazute

– Daca se fac apeluri multiple ale aceleiasi functii, erorile returnate de acea functie sunt tratate o singura data, intr-un singur loc

• Erorile nu mai pot fi ignorate.– Daca o functie trebuie sa transmita un mesaj de eroare apelantului,

acea functie va arunca (throw) un obiect reprezentand eroarea in afara functiei.

– Daca apelantul nu prinde (catch) eroarea si nu o trateaza, acest obiect este aruncat mai departe pana cand fie este tratat, fie programul se termina deoarece nu a existat nici un handler pentru eroare.

Page 8: Tratarea Exceptiilor.Spatii de nume. I/O

Aruncarea unei exceptii• Daca in cod apare o situatie

exceptionala si nu exista suficienta informatie pentru a fi tratata, informatia poate fi transmisa mai departe, intr-un context unde situatia poate fi rezolvata

• Transmiterea informatiei se realizeaza prin intermediul unui obiect care contine informatie relevanta despre situatia intalnita

• Obiectul este aruncat in afara contextului = aruncarea unei exceptii

MyException.h#ifndef MY_EXCEPTION_H#define MY_EXCEPTION_Hclass MyException{ const char* err_msg; public: MyException(const char* const m):err_msg(m)

{ }};#endif

Test.cpp#include "MyException.h"

void f(){ throw MyException("Mesaj");}int main(){ f(); return 0;}

Page 9: Tratarea Exceptiilor.Spatii de nume. I/O

Aruncarea unei exceptii• Throw:

– Se creeaza o copie a obiectului aruncat– Se returneaza aceasta copie din functia in care a fost intalnit,

chiar daca functia nu returna tipul de data al exceptiei in mod natural

– Executia continua intr-o parte speciala a codului – handlerul exceptiei

– Toate obiectele locale create in scopul in care a fost aruncata exceptia sunt distruse (“stack unwinding”)

– Se pot arunca oricate tipuri de exceptii este necesar– In mod obisnuit, pentru fiecare tip de anomalie se va arunca un

tip de exceptie diferit– Informatia este salvata in obiect, iar numele clasei exceptie

trebuie sa reflecte anomalia (Java: IOException, ClassNotFoundException, NullPointerException, IndexOutOfBoundsException, FileNotFoundException, etc)

Page 10: Tratarea Exceptiilor.Spatii de nume. I/O

Aruncarea unei exceptii

• Se poate arunca orice tip de data (inclusiv tipuri de date predefinite), dar de obicei se creeaza clase speciale

Page 11: Tratarea Exceptiilor.Spatii de nume. I/O

Prinderea unei exceptii

• Se realizeaza in interiorul unui handler de exceptie• Este nevoie de cate un handler de exceptie pentru fiecare tip de

exceptie care se doreste a fi prinsa• Daca in interiorul unei functii se arunca o exceptie sau se apeleaza

o functie care arunca o exceptie, corpul functiei este parasit din cauza exceptiei aruncate

• Daca se doreste ca aparitia lui throw in interiorul functiei sa duca la parasirea corpului functiei – bloc special in care se incearca rezolvarea problemei – blocul try

• Blocul try-catch – domeniu de vizibilitate normal

try{

//cod susceptibil (de exceptii)

}

Page 12: Tratarea Exceptiilor.Spatii de nume. I/O

Tratarea exceptiilor

• Handlerii de exceptii apar imediat dupa blocul try• Marcati prin cuvantul cheie catch

try{//cod susceptibil

….

}catch(Tip_1 id_1){//handler de exceptie Tip_1}

catch(Tip_2 id_2) {//handler de exceptie Tip_2}

catch(Tip_n id_n) {//handler de exceptie Tip_n}

Similar argumentelor unei functii

Page 13: Tratarea Exceptiilor.Spatii de nume. I/O

Exceptii

• 3 participanti la aruncarea/tratarea unei exceptii:

– Blocul try – marcheaza codul care ar putea sa genereze situatii de eroare

– Clauza catch – urmeaza imediat blocului try si contine codul care trateaza problema

– Instructiunea throw – modul in care codul cu probleme notifica codul apelant legat de aparitia unei probleme

Page 14: Tratarea Exceptiilor.Spatii de nume. I/O

Alocarea memoriei cu tratarea exceptiilor

#include <iostream>using namespace std;

int main(){ int* buf; try{ buf=new int[256]; if (buf==NULL) throw "Alocarea memoriei esuata!"; else delete [] buf; } catch (char* exc){ cerr<<exc<<endl; } return 0;}

Blocul TRY

Blocul CATCH

Instructiunea THROW

Page 15: Tratarea Exceptiilor.Spatii de nume. I/O

Constructori si destructori

• Controlul trece de la punctul in care apare THROW la un handler

• Obiectele create in scopul in care a fost aruncata exceptia sunt distruse AUTOMAT prin apelul destructorilor

• Daca constructorul unui element al unui vector arunca o exceptie, numai elementele construite ale vectorului vor fi distruse

Page 16: Tratarea Exceptiilor.Spatii de nume. I/O

Potrivirea exceptiilor

• La aruncarea unei exceptii, se cauta cel mai “apropiat” handler in raport cu ordinea in care acestia apar in cod

• La gasirea unei potriviri, cautarea se opreste

• Polimorfismul functioneaza

• E indicat sa prindem o exceptie prin referinta, pentru a evita apelul constructorului de copiere sau folosind pointeri

• Nu se fac conversii automate de tip in procesul de potrivire a exceptiilor

Page 17: Tratarea Exceptiilor.Spatii de nume. I/O

Conversii automate#include <iostream>

using namespace std;

class Exc1{

};

class Exc2{

public:

Exc2(Exc1){}

};

void f(){

throw Exc1();

}

int main(){

try{

f();

}catch(Exc2& e){cout<<"Exceptia 2"<<endl;}

catch(Exc1& e){cout<<"Exceptia 1"<<endl;}

return 0;

}

Constructor de conversie

Se executa deoarece NU se fac conversii automate de tip

Page 18: Tratarea Exceptiilor.Spatii de nume. I/O

Prinderea oricarui tip de exceptie

• Pentru a prinde orice tip de exceptie, se poate crea un handler care trateaza orice tip de exceptie folosind … pe postul listei de argumente

• catch(…){cout<<“orice exceptie “<<endl;}

• Este recomandat ca clauza catch(…) sa fie pusa ultima in lista handlerilor

Page 19: Tratarea Exceptiilor.Spatii de nume. I/O

Prinderea oricarui tip de exceptie

MyException.h

#ifndef MY_EXCEPTION_H#define MY_EXCEPTION_H

class MyException{ const char* err_msg; public: MyException(const char* const m):err_msg(m)

{} const char* const what(){return err_msg;}};

#endif

Test.cpp#include "MyException.h"#include <iostream>using namespace std;

void f(){ throw MyException("My Exception");}

int main(){try{ f();}catch(...) { cout<<"Nu se stie ce..."<<endl; } catch(MyException& e) {cout<<e.what()<<endl; } return 0;}

Se va intra pe aici

Page 20: Tratarea Exceptiilor.Spatii de nume. I/O

Rearuncarea unei exceptii

• Se doreste rearuncarea unei exceptii atunci cand exista niste resurse care trebuie eliberate (conexiuni in retea, memorie, etc)

• Se foloseste clauza throw fara nici un argument in interiorul unui handler

• De obicei, cand nu suntem interesati in cauza exceptiei, doar in a ne elibera resursele, folosim clauza catch(…) pentru a o prinde, a elibera resursele si apoi o aruncam mai departe

Page 21: Tratarea Exceptiilor.Spatii de nume. I/O

Rearuncarea unei exceptii

void g(){}

void f(){ char* s1; char* s2= new char[25]; try{ g(); }catch(...){delete [] s2; throw; } }

int main(){ f(); return 0;}

Page 22: Tratarea Exceptiilor.Spatii de nume. I/O

Rearuncarea unei exceptii#include <iostream>#include <fstream>using namespace std;void MyHandler(){ ifstream f("in.txt"); int m; try { f>>m; cout<<"m = "<<m<<endl; throw "hello"; f>>m; cout<<"m = "<<m<<endl; } catch (const char*) { f.close(); cout <<"Exceptie prinsa in MyHandler\n"; throw; //rethrow char* out of function }}int main(){ cout<< "Main start\n"; try { MyHandler(); } catch(const char*) { cout <<"Exceptie prinsa in Main\n"; } cout << "Main end"; return 0;}

Main startm=2Exceptie prinsa in MyHandlerExceptie prinsa in MainMain end

2 4

Page 23: Tratarea Exceptiilor.Spatii de nume. I/O

Exceptii neprinse

• Daca nici un handler nu trateaza o exceptie, se va apela functia terminate(), care apeleaza la randul sau abort() – iesirea din program

Page 24: Tratarea Exceptiilor.Spatii de nume. I/O

Specificarea exceptiilor

• Este posibila prezentarea multimii de exceptii pe care o functie le arunca direct sau indirect in cadrul declaratiei functiei– int getValue() throw (MyException*, char*, int);

• O functie fara nici o specificare a exceptiilor poate arunca orice exceptie– int f();

• O functie cu specificarea exceptiilor vida nu poate arunca nici o exceptie– int f () throw();

• Daca o functie arunca o exceptie nespecificata in lista exceptiilor va genera apelul functiei unexpected() →terminate()

Page 25: Tratarea Exceptiilor.Spatii de nume. I/O

Distrugerea obiectelor

• Sistemul de tratare a exceptiilor C++ garanteaza ca la parasirea domeniului de vizibilitate, toate obiectele create in acel domeniu de vizibilitate ai caror constructori s-au finalizat cu succes vor fi distruse prin apelarea automata a destructorilor

Page 26: Tratarea Exceptiilor.Spatii de nume. I/O

Distrugerea obiectelor#ifndef T_H#define T_H#include <iostream>using std::cout;

class Trace{ int objId; static int count;public: Trace(){objId=count++; cout<<"Object "<<objId<<"

created"<<endl; if(count==3) throw 3; } ~Trace() {cout<<"Destroying "<<objId<<endl;}};int Trace::count=0;#endif

#include "Trace.h"

int main(){try{Trace ob1;Trace array[5];Trace n2;}catch(int i){cout<<"Caught "<<i<<endl;}return 0;}

Object 0 createdObject 1 createdObject 2 created Destroying 1Destroying 0Caught 3

Nu se finalizeaza niciodata

Page 27: Tratarea Exceptiilor.Spatii de nume. I/O

Exceptii standard

• Derivate din clasa exception din <exception>

• 2 clase principale, definite in <stdexcept>, care include <exception>:– logic_error (transmiterea unui argument invalid, etc)– runtime_error (probleme hard, probleme cu memoria)

• Au cate un constructor cu argument de tip string (mesajul exceptiei)

• Metoda what() care returneaza mesajul de exceptie

Page 28: Tratarea Exceptiilor.Spatii de nume. I/O

Derivare din exceptii standard

#ifndef MY_EXC_H

#define MY_EXC_H

#include <stdexcept>

#include <iostream>

using namespace std;

class MyEx:public runtime_error{

public:

MyEx(const string& msg=""):runtime_error(msg){}

};

#endif

#include "MyException.h"

int main(){

try{

throw MyEx("mesaj ");

}catch(MyEx& e){cout<<e.what()<<endl;}

return 0;

}

Page 29: Tratarea Exceptiilor.Spatii de nume. I/O

Clase exceptie derivate

• Derivate din logic_error– domain_error– invalid_argument– length_error– out_of_range– bad_cast– bad_typeid

• Derivate din runtime_error– range_error– overflow_error– bad_alloc

Page 30: Tratarea Exceptiilor.Spatii de nume. I/O

Vector cu exceptii#ifndef ET_H#define ET_H#include <stdexcept>using namespace std;class ExceptionTrace:public runtime_error{

public: ExceptionTrace( char* m):runtime_error(m){}~ExceptionTrace(){}};#endif

#ifndef FVE_H#define FVE_H#include <string.h>#include "ExceptionTrace.h"

class FullVectorException:public ExceptionTrace{

public:FullVectorException(char*m):ExceptionTrace(m){}~FullVectorException(){}

};#endif

#ifndef IOBE_H#define IOBE_H#include "ExceptionTrace.h"

class IndexOutOfBoundsException:public ExceptionTrace{

public:

IndexOutOfBoundsException(char*m):ExceptionTrace(m){}~IndexOutOfBoundsException(){}

};

#endif

Page 31: Tratarea Exceptiilor.Spatii de nume. I/O

Vector.h#ifndef VECTOR_H#define VECTOR_H#include "FullVectorException.h"#include "IndexOutOfBoundsException.h"

class Vector{int* elem;int dim;int capac;

public:Vector(int=10);Vector(const Vector&);void operator +=(int) throw(FullVectorException);int operator [](int) throw(IndexOutOfBoundsException);void realoc();int vid() throw();

int dimensiune() throw(); ~Vector();};#endif

Page 32: Tratarea Exceptiilor.Spatii de nume. I/O

Vector.cpp#include "Vector.h"#include <iostream>using namespace std;

Vector::Vector(int d){elem= new int[d];dim=0;capac=d;

}

Vector::Vector(const Vector& v){ elem= new int[v.dim]; for (int i=0;i<v.dim;i++) elem[i]=v.elem[i]; dim=v.dim;}

void Vector::operator +=(int x) throw(FullVectorException){if(dim>=capac) throw FullVectorException("E plin vectorul");elem[dim++]=x;

}

Vector::~Vector(){ delete [] elem;}

int Vector::operator [](int i) throw(IndexOutOfBoundsException){if (i>=dim) throw IndexOutOfBoundsException("Indexul e prea mare");if (i<0) throw IndexOutOfBoundsException("Indexul e negativ");return elem[i];

}

void Vector::realoc(){int* aux = elem;elem= new int[dim+dim/2];for (int i=0;i<dim;i++)

elem[i]=aux[i];

capac=dim+dim/2;delete []aux;cout<<"realoc";

}

int Vector::vid() throw(){return dim==0;

}

int Vector::dimensiune() throw(){ return dim;}

Page 33: Tratarea Exceptiilor.Spatii de nume. I/O

Test.cpp#include "Vector.h"#include <iostream>using namespace std;

int main(){Vector v;try{

try{for (int i=0;i<15;i++)

v+=i;for(int i=2;;--i)

cout<<v[i]<<"\n";}catch(FullVectorException& e){

cout<<e.what()<<endl; v.realoc(); v+=11; throw;

}

catch(IndexOutOfBoundsException& e1){

cout<<e1.what()<<endl; throw;

}

catch(ExceptionTrace& e){

cout<<e.what()<<endl;

}

catch (...)

{cout<< "altceva";}

}catch(ExceptionTrace& e){

cout<<e.what()<<endl;

}

for(int i=0;i<v.dimensiune();i++)

cout<<v[i]<<" ";

return 0;

}

Page 34: Tratarea Exceptiilor.Spatii de nume. I/O

Spatii de nume• Defineste un domeniu de vizibilitate in care nu pot fi folositi identificatori duplicati

• Un spatiu de nume poate fi divizat la randul sau in mai multe spatii de nume

• Crearea unui spatiu de nume – similar unei clase

• Crearea de aliasuri de nume:– Namespace NumeLuuuuung{}– Namepace nume= NumeLuuuuung;

namespace MyLib{ //declaratii} Fara “;”

Page 35: Tratarea Exceptiilor.Spatii de nume. I/O

Spatii de nume

• Definitia unui spatiu de nume poate sa apara numai la nivel global, sau in interiorul altui domeniu de vizibilitate

• Definitia unui spatiu de nume se poate realiza in mai multe fisiere

#ifndef HEADER1_H#define HEADER1_H

namespace MyLib{ int x; void f(){}}#endif

#ifndef HEADER2_H#define HEADER2_H#include "Header1.h"

namespace MyLib{ int y; void g(){}}#endif

#include "Header1.h"#include "Header2.h"

int main(){MyLib::x=3;MyLib::y=5;MyLib::f();return 0;

}

Page 36: Tratarea Exceptiilor.Spatii de nume. I/O

Spatii de nume anonime

namespace{

int i,j;

}

• Referirea la identificatori se face fara a folosi operatorul ::

i=0;

j=5;

Page 37: Tratarea Exceptiilor.Spatii de nume. I/O

Utilizarea spatiilor de nume

1. Utilizarea operatorului de rezolutie

2. Utilizarea directivei using pentru a introduce toate numele

3. Utilizarea declaratiei using pentru a introduce cate un nume pe rand

Page 38: Tratarea Exceptiilor.Spatii de nume. I/O

Utilizarea operatorului ::

namespace X{

class Y{

static int i;

public:

void f();

};

class Z;

void func();

}

int X::Y::i=0;

class X::Z{

int u,v;

public:

Z(int);

}

X::Z::Z(int i){..}

void X:: func(){}

Page 39: Tratarea Exceptiilor.Spatii de nume. I/O

Directiva using• Permite importarea unui spatiu de nume

integral

#ifndef NSINT_H#define NSINT_H#include <iostream>using namespace std;

namespace Int{

class Integer{int val;

public:Integer(int =0);Integer(const Integer&);const Integer& operator+();const Integer operator-();const Integer operator+(const Integer&) const;const Integer operator-(const Integer&) const;Integer& operator=(const Integer&);bool operator==(const Integer&)const;bool operator!=(const Integer&)const;const Integer& operator++();const Integer operator++(int);operator double();operator int();Integer& operator+=(const Integer&);char* toString();friend ostream& operator<<(ostream& , Integer& );friend istream& operator>>(istream& , Integer& );

};

}#endif

Integer.cpp#include "NamespaceInt.h"using namespace Int;

Integer::Integer(int x):val(x){}

Integer::Integer(const Integer& x){val=x.val;

}

Integer::operator double(){ return double(val);}

Integer::operator int(){ return val;}const Integer& Integer::operator+(){

return *this;}

const Integer Integer::operator-(){ // cout<<"aa";

//if (val<0) return Integer(-val);

return Integer(-val);}

const Integer Integer::operator+(const Integer& a) const{return Integer(val+a.val);

}

Page 40: Tratarea Exceptiilor.Spatii de nume. I/O

Directiva using#ifndef NSM_H

#define NSM_H

#include "NamespaceInt.h"

namespace Math{ using namespace Int;

Integer a,b;

}#endif

#include "NamespaceMath.h"

using namespace Math;

int main(){

Integer a(6);

Integer c(8);

Integer sum=Math::a+c;

cout<<sum.toString()<<endl;

return 0;

}

Page 41: Tratarea Exceptiilor.Spatii de nume. I/O

Declaratia using

• Permite injectarea numelor dintr-un spatiu de nume unul cate unul

#ifndef UV_H#define UV_H#include <iostream>using namespace std;

namespace U{

inline void f(){cout<<"U::f()"<<endl;} inline void g(){cout<<"U::g()"<<endl;}}

namespace V{

inline void f(){cout<<"V::f()"<<endl;} inline void g(){cout<<"V::g()"<<endl;}}

#endif

#include "UV.h"

int main(){using namespace U;

f();

using V::f;f();g();U::f();return 0;}

U::f()V::f()U::g()U::f()

Page 42: Tratarea Exceptiilor.Spatii de nume. I/O

Declaratia using

#include <iostream>

int main(){

using std::cout;

using std::endl;

cout<<“Hello"<<endl;

return 0;

}

Page 43: Tratarea Exceptiilor.Spatii de nume. I/O

Spatii de nume imbricate (nested)

namespace A{ int i=5,j; inline f(){} namespace B{ int i=3; }}

#include <iostream>

using namespace std;#include "Namespace.h"

int main(){using namespace A;

cout<<A::i<<endl;cout<<A::B::i<<endl;return 0;}

53

Page 44: Tratarea Exceptiilor.Spatii de nume. I/O

Intrari/Iesiri (I/O)

• C: printf(…);scanf(…)

• Neajunsuri:– Lucreaza doar cu cele 4 tipuri de date predefinte (char, int, float,

double) si variatiile lor – nu este extensibila

• Posibila solutie:– Pentru fiecare tip de data nou introdus sa se supraincarce

functiile printf, scanf

• DAR– Stringul de formatare????

• Solutia:– Utilizarea STREAMURILOR

Page 45: Tratarea Exceptiilor.Spatii de nume. I/O

Stream-uri

• Definitie : un stream este un obiect care transporta si formateaza caractere de o lungime fixa (un flux de date de la o sursa (tastatura, fisier, zona de memorie) la o multime de destinatii (iesire: ecran, fisier, memorie)

• Caracteristica esentiala a procesarii streamurilor – datele sunt transmise sau primite de la un stream unul cate unul (serial)

• Tipuri de streamuri:– Streamuri de intrare (descendenti ai clasei istream)– Streamuri de iesire (descendenti ai clasei ostream)– Streamuri de intrare/iesire (descendenti ai clasei iostream)

Page 46: Tratarea Exceptiilor.Spatii de nume. I/O

Ierarhia de clase I/Oios

istream ostream

iostream

istream_withassign ostream_withassign

iostream_withassign

Declara tot ce este comun tuturor streamurilor

Defineste functii generice pentru iesire

Defineste functii generice pentru intrare

Page 47: Tratarea Exceptiilor.Spatii de nume. I/O

Iostream

• In biblioteca iostream – 2 operatori supraincarcati:– << (inserter) (folosit cu obiectul cout)– >>(extractor) (folosit cu obiectul cin)

• Pentru a salva timp la compilare in proiectele mari, e bine sa nu se includa <iostream>, ci <iosfwd>

#include <iosfwd>class Date{

friend std::ostream& operator<<(std::ostream&, const Date&);friend std::istream& operator>>(std::istream&, Date&);

};

Page 48: Tratarea Exceptiilor.Spatii de nume. I/O

Citirea de linii

• In mod obisnuit cin>> se opreste la primul blank

• Pentru a citi linii intregi – 3 posibilitati:

1. Functia membru get

2. Functia membru getline

• 3 argumente:

– Pointer la char – bufferul unde se va retine rezultatul

– Dimensiunea bufferului

– Caracterul de terminare (implicit ‘\n’)

• Diferente:

– get se opreste la primul caracter terminator, dar nu-l extrage

– getline extrage caracterul terminator, dar nu il pune in buffer

3. Functia globala getline <string>

– Citeste intr-un string

Page 49: Tratarea Exceptiilor.Spatii de nume. I/O

Get/getline membre

• Get

char* linie=new char[250];

cin.get(linie, 250);

cout<<linie<<endl;

while(strlen(linie)!=0){

cin.get();

cin.get(linie,250);

cout<<linie<<endl;

}

cin.get();

• Getline

char* linie=new char[250];

cin.getline(linie, 250);

cout<<linie<<endl;

while(strlen(linie)!=0){

cin.getline(linie,250);

cout<<linie<<endl;

}

Page 50: Tratarea Exceptiilor.Spatii de nume. I/O

Starea unui stream

• 4 flaguri folosite pentru a testa starea unui stream

• Valoarea unui flag poate fi testata apeland functiile:– good() – testeaza goodbit

– eof() –testeaza eofbit+failbit

– fail()- failbit sau badbit

– bad() - badbit

Flag Semnificatie

badbit Eroare fizica – eroare fatala, streamul nu mai poate fi folosit

eofbit A fost intalnit sfarsitul inputului

failbit Operatia de I/O a esuat (date invalide)

goodbit Nu sunt erori

Page 51: Tratarea Exceptiilor.Spatii de nume. I/O

Starea unui stream

• Pentru a schimba starea unui flag – clear()• Pentru a seta un flag: setstate(…)

myStream.setstate(ios::failbit)myStream.setstate(ios::badbit)

Page 52: Tratarea Exceptiilor.Spatii de nume. I/O

Starea unui stream#ifndef DATE_H#define DATE_H#include <iostream>#include <iomanip>using namespace std;

class Date{int day, month, year;

public:friend istream& operator>>(istream& is, Date& d);friend ostream& operator<<(ostream& os, const Date&);

};

istream& operator>>(istream& is, Date& d){is>>d.day;char slash='/';is>>slash;if (slash!='/')

is.setstate(ios::failbit);

is>>d.month;is>>slash;if(slash!='/')

is.setstate(ios::failbit);is>>d.year;return is;

}

ostream& operator<<(ostream& os, const Date& d){char fillc=os.fill('0');

os<<setw(2)<<d.day<<"/"<<setw(2)<<d.month<<"/"<<setw(4)<<setfill(fillc)<<d.year<<endl;return os;

}#endif

TEST.CPP#include "Date.h"#include <conio.h>using namespace std;int main(){Date d;cout<<"Introduceti data: ";cin>>d;if(cin.fail()) cout<<"Data in format

necorespunzator!"<<endl;else cout<<"Data introdusa este: "<<d;

return 0;}

Page 53: Tratarea Exceptiilor.Spatii de nume. I/O

Streamuri de tip fisier

• Pentru a deschide un fisier – se creeaza un obiect, iar constructorul deschide fisierul

• Fisierul nu trebuie inchis explicit – destructorul este apelat automat

• Pentru a crea un fisier – de intrare – ifstream– de iesire – ofstream– ambele - fstream

Page 54: Tratarea Exceptiilor.Spatii de nume. I/O

Moduri de deschidere a unui fisier• Se poate specifica modul de deschidere prin suprascrierea valorilor implicite

ale argumentelor constructorilor – folosim flaguri

• Fiecare obiect iostream contine un pointer la un obiect de tip streambuf – metoda rdbuf

Flag

ios::in Deschide un fisier de intrare

ios::out Deschide un fisier de iesire

ios::app Deschide un fisier de iesire pentru adaugare

ios::ate Deschide un fisier existent si se pozitioneaza la sfarsit

ios::trunc Trunchiaza fisierul daca exista deja

ios::bin Deschide un fisier in mod binar – implicit este text

Page 55: Tratarea Exceptiilor.Spatii de nume. I/O

Metoda rdbuf

#include <fstream>using namespace std;

int main(){ifstream f(“int.txt”);if(!f.fail())

cout<<f.rdbuf();return 0;

}

Tipareste pe ecran continutul fisierului

Page 56: Tratarea Exceptiilor.Spatii de nume. I/O

Pozitionarea in streamuri de I/O

• 2 modele:– Locatie absoluta – streampos– Locatie relativa – fseek – trece peste un numar de octeti de la

inceput, sfarsi, pozitia curenta

• Streampos– Prima data trebuie apelata functia “tell”

• tellp() - pentru ostream (put pointer)• tellg() – pentru istream (get pointer)

– Returneaza un pointer care poate fi folosit de catre functiile seekp() si seekg()

Page 57: Tratarea Exceptiilor.Spatii de nume. I/O

Pozitionarea in streamuri

• fseek – pozitionare relativa-foloseste versiuni supraincarcate ale lui seekp, seekg

• 2 argumente– Numarul de caractere peste care se face pozitionarea (poate fi

<0)– Directia de pozitionare:

• ios::beg (de la inceputul streamului)• ios::cur (de la pozitia curenta)• ios::end (de la sfarsitul streamului)

Page 58: Tratarea Exceptiilor.Spatii de nume. I/O

Pozitionarea in streamuri#include <fstream>#include <iostream>#include <conio.h>using namespace std;

int main(){ofstream out("a.txt");

out<<"Prima linie"<<endl;ofstream::pos_type p = out.tellp();out<<"A doua linie"<<endl;out.seekp(p);out.close();char* linie = new char[20];ifstream in("a.txt");

if(!in.fail()){//ma repozitionez unde am fost inaintein.seekg(p);//citesc si tiparesc

in.getline(linie, 20); cout<<linie<<endl;}else{cout<<"Eroare la deschidere";}

//de la pozitia curenta merg 5 caractere inapoiin.seekg(-5, ios::cur); in.getline(linie,20);cout<<linie<<endl;in.seekg(0, ios::beg); in.getline(linie,20);cout<<linie<<endl;

return 0;}

Page 59: Tratarea Exceptiilor.Spatii de nume. I/O

Formatarea streamurilor de iesire

• 2 modalitati:– Folosind functii membre– Manipulatori

• Flaguri de formatare– Clasa ios contine date membre care retin toate informatiile de

formatare• Variabile (precizia pentru date flotante, latimea campului de

iesire, caracterul cu care se completeaza iesirea)• Flaguri de formatare - restul

Page 60: Tratarea Exceptiilor.Spatii de nume. I/O

Flaguri de formatare

• 2 tipuri de flaguri:

– On/off

– Flaguri care lucreaza in grupuri

• Flaguri on/off

– Se seteaza cu setf(flag)/unsetf(flag)

Flag Efect

ios::skipws Sare peste caracterele albe

ios::showbase Pentru valorile intregi afiseaza baza

ios::showpoint Afiseaza punctul zecimal si zerouri de la coada pentru valori reale

ios::uppercase Afiseaza A-F pentru valori hexa

ios::showpos Afiseaza “+” pentru valorile pozitive

Ios:unitbuf Streamul este golit (flushed) dupa fiecare inserare

Page 61: Tratarea Exceptiilor.Spatii de nume. I/O

Campuri de formatare

• Flagurile de formatare lucreaza in grupuri, numai unul din flaguri poate fi setat la un moment dat

• Grupuri:– ios::basefield– ios::floatfield– ios::adjustfield

ios::basefield

ios::dec Formateaza valorile intregi in baza 10

ios::hex Formateaza valorile intregi in baza 16

ios::oct Formateaza valorile intregi in baza 8

Page 62: Tratarea Exceptiilor.Spatii de nume. I/O

Campuri de formatare

ios::floatfield

ios::scientific Format stiintific

ios::fixed Format fix

ios::adjustfield

ios::left Aliniere la stanga

ios::right Aliniere la dreapta

ios::internal Adauga caracterul de umplere (fill) intre semn si valoare

Page 63: Tratarea Exceptiilor.Spatii de nume. I/O

Dimensiune, umplere si precizie - functii

Functie Efect

int ios::width() Returneaza dimensiunea curenta

int ios::width(int n) Seteaza dimensiunea

int ios::fill Returneaza caracterul de umplere

int ios::fill(int n) Seteaza caracterul de umplere, returneaza anteriorul

int ios::precision() Returneaza precizia pt valori flotante (implicit 6)

int ios::precision(int n)

Seteaza precizia

Page 64: Tratarea Exceptiilor.Spatii de nume. I/O

Manipulatori

• Dubleaza actiunile realizate de functiile membre• Schimba starea streamului in loc de a procesa date

Page 65: Tratarea Exceptiilor.Spatii de nume. I/O

Manipulator Exemplu

showbase

noshowbase

showpos

noshowpos

uppercase

nouppercase

showpoint

noshowpoint

skipws

noskipws

left

right

internal

scientific

fixed

Page 66: Tratarea Exceptiilor.Spatii de nume. I/O

Manipulatori cu argumente

• <iomanip.h>

• setiosflags(formatFlags);

• resetiosflags(…)

• setbase(base)

• setfill(char)

• seprecision(int)

• setw(int)

cout<<setiosflags(ios::hex|ios::uppercase|ios::showpos);

cout<<a;

cout<<setbase(ios::hex)<<i<<endl;

cout<<setfill(‘ ‘)<<setw(20)<<5;

Page 67: Tratarea Exceptiilor.Spatii de nume. I/O

#include <fstream>#include <iostream>#include <iomanip>#include <conio.h>using namespace std;

int main(){ ofstream trc("trace.out"); int i = 47; float f = 2300114.414159; char* s = "Is there any more?"; trc << setiosflags(ios::unitbuf| ios::showbase |

ios::uppercase| ios::showpos); trc << i << endl; // Default to dec trc << hex << i << endl; trc << resetiosflags(ios::uppercase) << hex << i << endl; //aliniem la stanga trc.setf(ios::left, ios::adjustfield); trc << resetiosflags(ios::showbase)<< dec << setfill('0'); trc << "fill char: " << trc.fill() << endl; trc << setw(10) << i << endl;

//aliniem la dreapta // trc.setf(ios::right, ios::adjustfield); trc<<"ACUM ALNIEM LA DREAPTA"<<endl; trc <<right<<setw(10) << i << endl; //aliniem internal trc<<"ACUM ALNIEM INTERNAL"<<endl; // trc.setf(ios::internal, ios::adjustfield);//sau trc <<internal<< setw(10) << i << endl; trc << i << endl; // Without setw(10)

Trace.out

+470X2F0x2f

fill char: 0+470000000

ACUM ALINIEM LA DREAPTA0000000+47

ACUM ALINIEM INTERNAL

+000000047+47

Page 68: Tratarea Exceptiilor.Spatii de nume. I/O

trc << resetiosflags(ios::showpos)<< setiosflags(ios::showpoint)<< "prec = " << trc.precision() << endl;

trc.setf(ios::scientific, ios::floatfield); trc<< setiosflags(ios::uppercase)<<f<<endl; trc <<resetiosflags(ios::uppercase)<<f<<endl;

trc.setf(ios::fixed, ios::floatfield); trc<<f<<endl;

trc << setprecision(20); trc << "prec = " << trc.precision() << endl; trc << f << endl;

trc.setf(ios::scientific, ios::floatfield); trc << f << endl;

trc << setw(10) << s << endl; trc<<setfill(' ')<<setw(40) << s << endl; //trc << setw(40) << s << endl;

// trc.setf(ios::left, ios::adjustfield); trc << left<<setw(40) << s << endl; return 0;}

prec = 6

2.300115E+0062.300115e+006

2300114.500000

prec = 202300114.50000000000000000000

2.30011450000000000000e+006

Is there any more? Is there any more?

Is there any more?