PDA

Visualizza la versione completa : [C++] Utilizzo di throw per sollevare eccezioni all'interno delle funzioni


giuseppe500
04-07-2012, 13:28
ciao.
Al lavoro lavoriamo su un software senza mai gestire ne utilizzare nessun tipo di eccezione.
Quando ci serve un po di diagnostica facciamo ritornare alla funzione un int che rappresenta il codice di un errore e che viene impostato nella funzione stessa.
Ho letto un po su google che un eccezione puo' essere una classe e si presta meglio a ritornare errori piu dettagliati , ma solo questo?
perch usare un trow in una funzione? dove sono i vantaggi?
Ho visto che linguaggi "piu evoluti" o meglio piu moderni fanno largo uso di eccezioni , ma questo forse perch spesso sono interpretati e si puo "recuperare l'errore"(non piantarsi).

grazie.

Scara95
04-07-2012, 13:40
Si pu benissimo anche in C++: esiste un catch...
I vantaggi di utilizzare gli errori sono fondamentalmente:
-avere maggiori informazioni sull'errore
-non dover riaddattare la funzione per farle ritornare un int (ad esempio)
-poter propragare l'errore e gestirlo in altri punti
-tenere fortemente separati il codice funzionale e quello di gestione degli errori (che dovrebbero essere usati solo per situazioni "patologiche", che non dovrebbero verificarsi...

Quest'ultimo punto risulta in un codice pi comprensibile e gestibile in quanto riesci a distinguere pi facilmente cosa fa la funzione tenendo la gestione delle eccezioni in un blocco visibilmente separato.

MItaly
04-07-2012, 14:32
Inoltre con le eccezioni non rischi di ignorare un errore (per la pigrizia di non controllare sempre cosa restituisce una funzione), e le eccezioni risalgono automaticamente lo stack fino a trovare un gestore adeguato. Ovviamente questo ha anche dei downside: ogni istruzione diventa un potenziale punto di uscita della funzione, per cui risulta indispensabile l'uso di tecniche come la RAII per la gestione delle risorse.

Scara95
04-07-2012, 14:37
Originariamente inviato da MItaly
Ovviamente questo ha anche dei downside: ogni istruzione diventa un potenziale punto di uscita della funzione, per cui risulta indispensabile l'uso di tecniche come la RAII per la gestione delle risorse.
Esiste anche il blocco finally che pu essere usato per la gestione della memoria ed (eventualmente) rilanciare l'errore...

Scara95
04-07-2012, 14:45
Ok, mi correggo, ho detto una cavolata! Momento di confusione fra linguaggi...

giuseppe500
04-07-2012, 14:50
grazie gente.
ma per es , ho il seguente codice:


virtual void insert(const T& value = getUnset(T())) throw(std::out_of_range)
{
setUnset(false);
m_id = CDebug::Add();
m_id = m_id;
std::set<T>::insert(value);
if (_hi>0)
{
if (Integer(std::set<T>::size())>_hi)
{
std::set<T>::erase(value);
throw std::out_of_range("Set is full");
}
}
}


possibile ottenere un errore piu dettagliato ?
ho letto che si puo usare qualcosa tipo "what()" ma non ho capito bene.

grazie

giuseppe500
04-07-2012, 14:55
se puo servire qu c' il codice della classe :


// IFC SDK : IFC2X3 C++ Early Classes
// Copyright (C) 2009 CSTB
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full license is in Licence.txt file included with this
// distribution or is available at :
// http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.

#ifndef Step_Set_h
#define Step_Set_h

#include "SimpleTypes.h"

#include <set>
#include <stdexcept>
#include "Debug.h"
#ifdef _MSC_VER
#pragma warning(disable:4290)
#endif

#ifdef __GNUC__
# define GLIBCXX_HAS_DEFECTS 1
#endif

namespace Step {
/*!
** \short C++ implementation of EXPRESS container 'SET'
** based on hash_set
*/

template<typename T, Integer _lo = 0, Integer _hi = -1> class Set :
public std::set<T>,
public Aggregate
{
public:
//! the size_type
typedef typename std::set<T>::size_type size_type;
//! the forward iterator
typedef typename std::set<T>::iterator iterator;
//! the const forward iterator
typedef typename std::set<T>::const_iterator const_iterator;
//! the reverse iterator
typedef typename std::set<T>::reverse_iterator reverse_iterator;
//! the const reverse iterator
typedef typename std::set<T>::const_reverse_iterator const_reverse_iterator;
long m_id;
/**
* Default constructor
* \param unset initialized to not unset by default
*/
Set(bool unset=false) : Aggregate(unset)
{
m_id = 0;
}

/**
* constructor with initialization with an array
* \param value an array of values
* \param count the number of elements to insert from the array in value
* \throws std::range_error
*/
Set(const T value[], Integer count) throw(std::range_error)
{
for (Integer i=0; i<count; ++i)
insert(value[i]);

if (Integer(std::set<T>::size())<_lo)
{
std::set<T>::clear();
throw std::range_error("Set : array not big enough");
}
if (_hi>0)
{
if (Integer(std::set<T>::size())>=_hi)
{
std::set<T>::clear();
throw std::range_error("Set size is not big enough for the array");
}
}
}

/**
* constructor with initialization with a std::vector
* \param value a list of values
* \throws std::range_error
*/
Set(const std::vector<T>& value) throw(std::range_error)
{
if (Integer(std::set<T>::size())<_lo)
{
std::set<T>::clear();
throw std::range_error("Set : vector not big enough");
}
if (_hi>0)
{
if (Integer(std::set<T>::size())>=_hi)

{
std::set<T>::clear();
throw std::range_error("Set size is not big enough for the vector");
}
}
for (unsigned i=0;i<value.size();++i)
{
insert(value[i]);
}
}

#ifndef GLIBCXX_HAS_DEFECTS
/**
* constructor with initialization with a std::list
* \param value a list of values
* \throws std::range_error
*/
Set(const std::list<T>& value) throw(std::range_error)
{
if (Integer(std::set<T>::size())<_lo)
{
std::set<T>::clear();
throw std::range_error("Set : list not big enough");
}
if (_hi>0)
{
if (Integer(std::set<T>::size())>=_hi)
{
std::set<T>::clear();
throw std::range_error("Set size is not big enough for the list");
}
}
std::copy(value.begin(),value.end(),this->begin());
}
#endif
virtual ~Set()
{
}

/**
* The set container is extended by inserting a single new element
* \param value value to insert
* \throws std::range_error
*/
virtual void insert(const T& value = getUnset(T())) throw(std::out_of_range)
{
setUnset(false);
m_id = CDebug::Add();
m_id = m_id;
m_id = _hi;
std::set<T>::insert(value);
if (_hi>0)
{
if (Integer(std::set<T>::size())>_hi)
{
std::set<T>::erase(value);
throw std::out_of_range("Set is full");
}
}
}

/**
* erase a value at a given position
* \param it where to erase
*/
virtual void erase(iterator &it)
{
std::set<T>::erase(it);
}

/**
* erase a value at a given position
* \param value to erase.
* \return the function returns the number of elements erased, which in set containers is 1 if an element with a value of x existed (and thus was subsequently erased), and zero otherwise.
*/
virtual size_type erase(const T &value)
{
return std::set<T>::erase(value);
}

/**
* get the upper bound of the Set
* \return the upper bound if set, getUnset() if not.
*/
virtual inline Integer getUpperBound()
{
if (_hi>0)
{
return _hi;
}
else {
return getUnset(_hi);
}
}

/**
* get the lower bound of the List
* \return the lower bound.
*/
virtual inline Integer getLowerBound()
{
return _lo;
}

/**
* Assigns a copy of Set other as the new content for the Set object.
* \param other A Set object containing elements of the same type.
* \return a reference to this Set
*/
Set& operator=(const Set& other)
{
this->setUnset(other.isUnset());
std::set<T>::operator=(other);
return *this;
}
private:
// cannot allow to have an operator that will allow different sizes of Set to be assigned
std::set<T>& operator=(const std::set<T>& other);
};

// UNSET for SET
template<typename T, Integer _lo, Integer _hi> inline Set<T,_lo,_hi> &getUnset(Set<T,_lo,_hi>)
{
static Set<T,_lo,_hi> unset(true);
return unset;
}
}

#endif

giuseppe500
04-07-2012, 14:57
e qu l'altra classe da cui deriva (Aggregate)


// IFC SDK : IFC2X3 C++ Early Classes
// Copyright (C) 2009 CSTB
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full license is in Licence.txt file included with this
// distribution or is available at :
// http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.

#ifndef Step_SimpleTypes_h
#define Step_SimpleTypes_h

#include "Binary.h"
#include "Referenced.h"
#include "String.h"

#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <limits>
#include <locale>

#if defined (linux)
# include <stdexcept>
#endif

namespace Step {

//! Integer type
typedef __int32 Integer;

//! Real type
typedef double Real;

//! Number type
typedef Real Number;

//! Boolean type
enum Boolean
{
BUnset, BFalse, BTrue
};

//! Logical type
enum Logical
{
LUnset, LFalse, LTrue, LUnknown
};

class Unset;

bool isUnset(const Unset& u);

class BaseObject;

/*!
\short Base Class for Aggregations which need a flag 'unset'
This flag is used to distinguish a parameter with an empty list from an unset parameter
*/
class Aggregate: public Referenced
{

public:

/*!
\short Constructor from a flag
@param b the 'unset' flag
*/
Aggregate(bool b = false) :
m_unset(b)
{
}

/*!
\short Gets the 'unset' flag
@return the 'unset' flag
*/
bool isUnset() const
{
return m_unset;
}

/*!
\short Sets the 'unset' flag
@param b the 'unset' flag
*/
void setUnset(bool b)
{
m_unset = b;
}

/*!
\short Toggle the 'unset' flag
@return The new state of the 'unset' flag
*/
bool toggleUnset()
{
m_unset = !m_unset;
return m_unset;
}

protected:
//! store if the unset status
bool m_unset;
};

//! getUnset values the String type
inline String getUnset(const String&)
{
return "Unset";
}

//! getUnset values the const BaseObject type
inline const BaseObject* getUnset(const BaseObject*)
{
return NULL;
}

inline BaseObject* getUnset(BaseObject*)
{
return NULL;
}

//! getUnset values the RefPtr type
template<typename T>
inline RefPtr<T> getUnset(RefPtr<T>&)
{
return NULL;
}

#ifdef max
#undef max
#endif

//! getUnset values the Integer type
inline Integer getUnset(Integer)
{
return std::numeric_limits<Integer>::max() ;
}

//! getUnset values the Real type
inline Real getUnset(Real)
{
return std::numeric_limits<Real>::max() ;
}

//! getUnset values the Boolean type
inline Boolean getUnset(Boolean)
{
return BUnset;
}

//! getUnset values the Logical type
inline Logical getUnset(Logical)
{
return LUnset;
}

//! getUnset values the Binary type
template<int N>
inline Binary<N> getUnset(Binary<N> )
{
return Binary<N> ();
}

//! isUnset method for the String type
inline bool isUnset(const String& v)
{
return v == getUnset(v);
}

//! isUnset method for the const BaseObject type
inline bool isUnset(const BaseObject* v)
{
return v == getUnset(v);
}

//! isUnset method for the BaseObject type
inline bool isUnset(BaseObject* v)
{
return v == getUnset(v);
}

//! isUnset method for the Integer type
inline bool isUnset(Integer v)
{
return v == getUnset(v);
}

//! isUnset method for the Real type
inline bool isUnset(Real v)
{
return v == getUnset(v);
}

//! isUnset method for the Enumerated type
inline bool isUnsetEnum(int i)
{
return i == 0;
}

//! isUnset method for the Boolean type
inline bool isUnset(Boolean v)
{
return v == getUnset(v);
}

//! isUnset method for the Logical type
inline bool isUnset(Logical v)
{
return v == getUnset(v);
}

//! isUnset method for the Binary type
template<int N>
inline bool isUnset(Binary<N> v)
{
return v.is_unset();
}

//! isUnset method for the Aggregate type
inline bool isUnset(const Step::Aggregate& u)
{
return u.isUnset();
}

//! isUnset method for the RefPtr type
template<typename T>
inline bool isUnset(RefPtr<T>&t)
{
return !t.valid();
}

template<class T>
T fromString(const std::string& s)
{
std::istringstream stream (s);
// Make sure not to be side tracked by user's locale
stream.imbue(std::locale::classic());
T t;
stream >> t;
return t;
}

//! spf parsing for Integer type
inline Integer spfToInteger(const std::string& s)
{
if (s != "$")
return fromString<Integer>(s);
else
return getUnset(Integer(0));
}

//! spf parsing for Real type
inline Real spfToReal(const std::string& s)
{
if (s != "$")
return fromString<Real>(s);
else
return getUnset(Real(0));
}

//! spf parsing for Boolean type
inline Boolean spfToBoolean(const std::string& s)
{
if (s == ".T.")
return BTrue;
else if (s == ".F.")
return BFalse;
else
return BUnset;
}

//! spf parsing for Logical type
inline Logical spfToLogical(const std::string& s)
{
if (s == ".T.")
return LTrue;
else if (s == ".F.")
return LFalse;
else if (s == ".U.")
return LUnknown;
else
return LUnset;
}

//! spf parsing for Bianry type
template<int N>
inline Binary<N> spfToBinary(const std::string& s)
{
Binary<N> b;
b.from_spfstring(s);
return b;
}
}

#endif

MItaly
04-07-2012, 15:12
Originariamente inviato da giuseppe500
grazie gente.
ma per es , ho il seguente codice:


virtual void insert(const T& value = getUnset(T())) throw(std::out_of_range)
{
setUnset(false);
m_id = CDebug::Add();
m_id = m_id;
std::set<T>::insert(value);
if (_hi>0)
{
if (Integer(std::set<T>::size())>_hi)
{
std::set<T>::erase(value);
throw std::out_of_range("Set is full");
}
}
}


possibile ottenere un errore piu dettagliato ?
ho letto che si puo usare qualcosa tipo "what()" ma non ho capito bene.

grazie

Nel momento in cui vai a richiamare insert da qualche parte nel call stack avrai inserito un gestore di eccezioni (eventualmente proprio attorno alla insert); quando catturi una const std::exception & o una classe che da essa deriva puoi usare il metodo what() per ottenere dettagli dell'errore. In ogni caso, in genere la descrizione cos ottenuta utile giusto come messaggio da visualizzare, se ci sono dati specifici relativi ad un particolare errore bene creare una classe-eccezione apposita e fornire tali dati come membri della classe.

giuseppe500
04-07-2012, 15:24
grazie Mitaly , ma non riesco a capire cosa fa quel codice, tu indicativamente riesci a capirlo?
poi,
la stesssa funzione per il vector cosi:


virtual void push_back(const T& value) throw(std::out_of_range)
{
setUnset(false);
if (_hi>0)
if (std::vector<T>::size()== (typename std::vector<T>::size_type)_hi)
throw std::out_of_range("List is full");
std::vector<T>::push_back(value);
}


cosa fa questa riga:
if (std::vector<T>::size()== (typename std::vector<T>::size_type)_hi)
e come funziona e cos _hi di preciso?
perch lo imposta a -1 ( un default?)
grazie.

Loading