PDA

Visualizza la versione completa : [C++] Confronto tra interi fallisce?


Ippo343
26-12-2010, 12:35
Ragazzi non ho idea di cosa stia succedendo...

In pratica io ho una funzione che lavora su una matrice quadrata. Se la riga o la colonna sono più grandi della dimensione della matrice deve sollevare un'eccezione. Così:



square_matrix square_matrix::suppress(unsigned int row, unsigned int column) const
throw (out_of_bounds_exception)
{
cout << "Debug couts:" << endl;
cout << "In square_matrix::suppress(unsigned, unsigned)." << endl;
cout << "_dim = " << _dim << endl;
cout << "row = " << row << endl;
cout << "column = " << column << endl;

if ( (row >= _dim) || (column >= _dim) )
throw out_of_bounds_exception();

...
}


Quando la chiamo dal main, così:



try
{
square_matrix B = A.suppress(0,0);
B.print();
}
catch(out_of_bounds_exception& ex)
{
cerr << "out_of_bounds_exception raised." << endl;
}


Ottengo questo output meraviglioso:



Debug couts:
In square_matrix::suppress(unsigned, unsigned).
_dim = 3
row = 0
column = 0
out_of_bounds_exception raised.


Cioè, ora, io ero convinto che (0 < 3)... no? I numeri in gioco sono tutti unsigned.
Qualcuno ha idea di cosa stia succedendo? :confused:

Ippo343
27-12-2010, 00:58
Problema risolto...

Era una domanda veramente stupida ^^

In realtà veniva sollevata la stessa identica eccezione più in giù nel metodo, quindi risaliva lo stack e arrivava dove la intercettavo convinto che arrivasse da lì.

MacApp
27-12-2010, 02:47
no, non è una cosa stupida; evidentemente il tuo modello per lanciare eccezioni:


if ( (row >= _dim) || (column >= _dim) )
throw out_of_bounds_exception();

ti ha fatto perdere tempo.

Meglio sarebbe un qualcosa del tipo:


RuntimeAssert ((row >= _dim) || (column >= _dim));

che in caso di fallimento "logghi" almeno __FILE__ e __LINE__ no?
;-)

ad esempio:



#define RuntimeAssert(theAssertion) YourRuntimeAssertFunction((theAssertion), __FILE__, __LINE__)

Ippo343
27-12-2010, 12:58
Più che altro è che più in giù nel metodo c'è una chiamata che può generare la stessa eccezione, e non ho pensato a intercettare anche quella.

L'idea di loggare file e linea mi sembra ottima, ma una volta risolto il problema vorrei di nuovo tornare alle eccezioni: questo perchè in sostanza quella funzione permette all'user di eliminare una riga e una colonna dalla matrice, ma come ben sai, tutto l'input è malvagio :)

Cioè, se l'utente inserisce riga e colonna sbagliati, viene sollevata un'eccezione, gli do del cretino, e può riprovare... Se il programma termina loggando l'errore bisogna riavviarlo da capo :)

MItaly
27-12-2010, 15:04
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define ERROR_STD_PROLOG "Exception thrown in function: " __FUNCSIG__ " (in " __FILE__ ", last modified on " __TIMESTAMP__ ", line " TOSTRING( __LINE__ ) ").\nMessage: "

Quindi:


throw out_of_range(ERROR_STD_PROLOG "Panico e morte!");

Occhio che aumenta un po' le dimensioni dell'eseguibile, dato che ogni messaggio (completo di signature della funzione, file e riga) viene salvato per i fatti suoi nella sezione stringhe dell'eseguibile. Ad un certo punto avevo fatto una classe eccezione più furba che memorizzava i pezzi separatamente, risparmiando un bel po' di spazio (tutti i vari __FILE__ e __TIMESTAMP__ dello stesso file vengono riciclati, e così pure i pezzi comuni a tutte le eccezioni), ma ora come ora non la trovo.

In verità la cosa più comoda di tutte sarebbe poter avere uno stack trace, ma non esiste un modo standard multipiattaforma per recuperarlo; esistono però diverse librerie che vengono in aiuto, e vedo che stanno pensando a qualcosa del genere in boost - il che sarebbe assai figo :D.

Ippo343
27-12-2010, 15:16
Non capisco il senso della macro TOSTRING: non la si può semplicemente definire come



#define TOSTRING(x) #x


?

MItaly
27-12-2010, 15:18
No, perché, per come funziona l'espansione delle macro, se definissi TOSTRING in quella maniera otterresti
"__LINE__", "__FILE__", eccetera. Il doppio passaggio è necessario perché le macro __LINE__, __FILE__ e compagnia vengano espanse nei loro effettivi valori prima di passare per l'operatore # che le rende stringhe ("65", "./test.cpp", ...).

Ippo343
27-12-2010, 15:22
Mmm, ho capito... più meno. brb testin'

Ippo343
27-12-2010, 15:31
Non funziona...

Ad ogni uso da una serie di errori "expected primary expression before '(' token" e poi il corrispondente "expected ')' before __FUNCSIG__"...

Eppure la macro mi sembra corretta :confused:

Ippo343
27-12-2010, 15:45
Ok, ho isolato il problema... se provo a fare:


throw exception( __FUNCSIG__ );

mi dice che __FUNCSIG__ non è definita in questo scope...

Loading