range-checked vector



  • Tachyon schrieb:

    Hast Du die letzten paar Posts auch mal gelesen?

    nein, der letzte Beitrag von pumuckl war noch nicht da, als ich meinen Beitrag geschrieben habe, der beantwortet dann ja eigentlich alle Fragen



  • pumuckl schrieb:

    ...
    - Wenn Range-Checks eingeschaltet sind, muss eine Exceptionbehandlung her, sonst hat man gegenüber der Version ohne Range-checks keine nennenswerten Vorteile: so oder so schmiert das Programm ab....

    Obwohl ich Dir im Grunde zustimme, würde ich in dem Detail widersprechen wollen: Wenn bei range violations Programme zuverlässig "abschmierten", wären sie viel ungefährlicher.
    So gesehen hätte IMHO ein range-checking auch ohne exception handling Wert. Man könnte sogar überlegen, statt einer exception direkt ein assert() "zuschlagen zu lassen" (wie jemand oben bereits vorschlug, glaube ich).

    Trotzdem bin ich im Kern immer noch Deiner Meinung.

    Gruß,

    Simon2.



  • ingobulla schrieb:

    Kann man das irgendwie anders mit typedef umsetzen oder muss man doch Präprozessor-Direktiven nutzen?

    template typedefs gehn leider wirklich nicht, daher muss man zu einem kleinen Kniff greifen:

    template <class T>
    struct Container
    {
      typedef std::vector<T> type;
      //oder typedef std::list<T> type;
      //oder typedef MyOwnVectorImpl<T> type;
    };
    
    //später:
    
    void blub()
    {
      Container<int>::type values;
      Container<myClass>::type myCont;
    
      //usw.
    }
    

    Sieht auf den ersten Blick nicht ganz so hilfreich aus, man spart schließlich kaum Tipparbeit - aber man kann den zugrundeliegenden Contyinertyp mit einer Zeile austauschen: im typedef im struct Container<T>.



  • pumuckl schrieb:

    Mal abgesehn von den bisherigen Diskussionen mal eine kleine Betrachtung ob das überhaupt sinnvoll ist:

    - Wenn Range-Checks eingeschaltet sind, muss eine Exceptionbehandlung her, sonst hat man gegenüber der Version ohne Range-checks keine nennenswerten Vorteile: so oder so schmiert das Programm ab.

    Das wäre schön, ist aber nicht zwangsläufig der Fall. Der VC++ hat in seiner STL-Implementierung range checks, sogar im Release build, da schmiert das Programm ab. Bei anderen STL-Implementierungen ist das nicht zwangsläufig der Fall.

    Ich bin auch nicht der Meinung, dass man bei der Verwendung von at() zwangsläufig ein Exception-Handling einbauen muss. Oft genug ist es akzeptabler, ein Programm abstürzen zu lassen als einen buffer overflow zu riskieren. Oft ist in der Nähe von main() einfach ein Exception Handler für alles, dann kann man wenigstens noch was ins logfile schreiben. An Ort und Stelle lassen sich diese Art von Fehlern imho kaum sinnvoll behandeln, da jede Alternative (zum Beispiel size() prüfen) einfacher zu implementieren ist.

    Wenns dir nur darum geht während der Entwicklung die Range zu überprüfen, nutz assert(), dazu ist das da (und wird im Releasemodus automatisch weggetriggert)

    Dieses assert bei jedem Zugriff auf den Vector einzubauen ist eben unpraktikabel. Ich vermute, der Threadersteller wünscht, dass der Test Teil des operator[] ist. Keine Ahnung ob du das gemeint hast, sollte man aber mal dazu schreiben.



  • Ich habe das jetzt mal versucht umzusetzen, im folgenden der Code. Erläuternd sei erstmal gesagt, dass

    • LoggerPtr ein Zeiger auf ein logger-Objekt der Logging-Bibliothek log4cxx ist
    • SAFE eine globale Konstante ist, die festlegt, ob das Programm in einem abgesicherten Modus betrieben werden soll
    • ERROR ein Makro ist, dass dafür sorgt, dass eine Fehlermeldung ausgegeben und geloggt wird
    #ifndef VECTOR_H_
    #define VECTOR_H_
    
    #include "control_consts.h"
    #include "error.h"
    
    #include <log4cxx/logger.h>
    
    #include <vector>
    #include <list>
    
    using namespace log4cxx;
    using namespace std;
    
    template<class T> class RVec : private vector<T>
    {
    private:
    	static LoggerPtr m_logger;
    	static LoggerPtr& logger() { return m_logger; }
    public:
    	using vector<T>::size;
    	using vector<T>::resize;
    	using vector<T>::front;
    	using vector<T>::back;
    	using vector<T>::push_back;
    	using vector<T>::pop_back;
    	using vector<T>::begin;
    	using vector<T>::end;
    	using vector<T>::rbegin;
    	using vector<T>::rend;
    	using vector<T>::iterator;
    	using vector<T>::reverse_iterator;
    	using vector<T>::const_iterator;
    	using vector<T>::const_reverse_iterator;
    	using vector<T>::reference;
    	using vector<T>::const_reference;
    	using vector<T>::clear;
    
    	RVec() : vector<T>() { }
    	RVec(int s) : vector<T>(s) { }
    	RVec(int s, T t) : vector<T>(s, t) { }
    	RVec(typename vector<T>::iterator it, typename vector<T>::iterator jt) : vector<T>(it, jt) { }
    	RVec(typename list<T>::iterator it, typename list<T>::iterator jt) : vector<T>(it, jt) { }
    	RVec(T* p, T* q) : vector<T>(p, q) { }
    
    	T& operator[](int i);
    	const T& operator[](int i) const;
    };
    
    template<class T> LoggerPtr RVec<T>::m_logger(Logger::getLogger("rvec"));
    
    template<class T> T& RVec<T>::operator[](int i)
    {
    	if (SAFE && (i < 0 || i >= size())) {
    		stringstream ss;
    		ss << "Index out of range: index = " << i << ", size = " << size();
    		throw ERROR(logger(), ss.str());
    	}
    	T& t = vector<T>::operator[](i);
    	return t;
    }
    
    template<class T> const T& RVec<T>::operator[](int i) const
    {
    	if (SAFE && (i < 0 || i >= size())) {
    		stringstream ss;
    		ss << "Index out of range: index = " << i << ", size = " << size();
    		throw ERROR(logger(), ss.str());
    	}
    	const T& t = vector<T>::operator[](i);
    	return t;
    }
    
    #endif
    

    Wenn ich nun aber den Code

    RVec<bool> is_act_site(Base_Nd<N, C, T>::num_sites());
    	...
    	for (int i = 0; i < left_most_act_site; ++i)
    		is_act_site[i] = false;
    

    ausführe, erhalte ich die Fehlermeldung

    ../src/rvec.h: In member function ‘T& RVec<T>::operator[](int) [with T = bool]’:
    ../src/node/base_nd_def.h:92: instantiated from ‘Base_Nd<N, C, T>::Base_Nd(T*, N*, N*, boost::variant<int, Empty, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>) [with N = Rev_Nd, C = Rev_NC, T = Rev_Tree]’
    ../src/node/base_nd.cpp:16: instantiated from here
    ../src/rvec.h:65: error: invalid initialization of non-const reference of type ‘bool&’ from a temporary of type ‘std::_Bit_reference’

    bzgl. Zeile 65 des obigen Codes und der Zeile

    is_act_site[i] = false;
    


  • hmpf. bau halt einfach ein assert im code vom vector ein.


Anmelden zum Antworten