vector mit unterschiedlichen Typen?



  • Copy-Constructor?

    return new A1( dynamic_cast< A1& >( b ) );
    

    Gedacht ist diese new_clone Funktion allerdings eher für virtuelles Klonen. Damit sparst Du Dir auch die (u.U. sehr langsamen) typeid-Vergleiche:

    class B
    {
        virtual B* clone();
    };
    
    class A1
    {
        virtual A1* clone() { return new A1( *this ); }
    };
    
    class A2
    {
        virtual A2* clone() { return new A2( *this ); }
    };
    
    B* new_clone( B const& b )
    {
        return b.clone();
    }
    


  • LordJaxom schrieb:

    Copy-Constructor?

    return new A1( dynamic_cast< A1& >( b ) );
    

    der richtige cast wäre static_cast , vor allem weil ja sowieso schon nach dem typeid klar ist, um welchen dynamischen typ es sich handelt. (mit dynamic_cast wäre so ein konstrukt besser:

    Base* new_clone (Base* b)
    {
      if (Derived* d = dynamic_cast<Derived*>(b))
      {
        return new Derived(*d);
      }
      //...
    }
    

    )

    warum "langsame typeid-vergleiche"?
    (natürlich ist deine lösung ("virtueller copy-ctor" clone) am elegantesten)



  • queer_boy schrieb:

    der richtige cast wäre static_cast , vor allem weil ja sowieso schon nach dem typeid klar ist, um welchen dynamischen typ es sich handelt. (mit dynamic_cast wäre so ein konstrukt besser:

    Hast natürlich recht, der dynamische hat hier mehr Overhead.

    warum langsame typeid-vergleiche?

    Weil ich mindestens eine Implementierung kenne (wenngleich die auch veraltet ist), die in type_info::operator== Stringvergleiche macht. Der virtuelle Aufruf ist nur eine Indirektion.



  • Danke für eure Hilfe. Ich habe es genau so implementiert (die Lösung mit dem Copy-Ctor), einziger Unterschied ist, dass ich das Schlüsselwort const weggelassen habe, weil ich einen Error

    passing 'const B' as 'this' argument of 'virtual B* B::clone()' discards qualifiers
    

    bekommen habe. Wenn noch jemand so nett ist und mir erläutert, wieso const in diesem Zusammenhang falsch ist, wäre ich glücklich fürs Erste 😉



  • SeniiX schrieb:

    Danke für eure Hilfe. Ich habe es genau so implementiert (die Lösung mit dem Copy-Ctor), einziger Unterschied ist, dass ich das Schlüsselwort const weggelassen habe, weil ich einen Error

    passing 'const B' as 'this' argument of 'virtual B* B::clone()' discards qualifiers
    

    bekommen habe. Wenn noch jemand so nett ist und mir erläutert, wieso const in diesem Zusammenhang falsch ist, wäre ich glücklich fürs Erste 😉

    du versuchst wahrscheinlich, eine nicht-konstante memberfunktion für ein konstantes objekt aufzurufen. da clone keine änderungen am objekt vornimmt, wäre es wahrscheinlich besser, bevor du überall const weglässt, clone eben zu einer konstanten memberfunktion zu machen:

    class Foo
    {
    public:
       Foo* clone () const { return new Foo(*this); }
    };
    


  • LordJaxom schrieb:

    Copy-Constructor?

    return new A1( dynamic_cast< A1& >( b ) );
    

    würde hier dem cast ein template vorziehen:

    template<class T>
    T* make_clone(const T& t)
    {
    	return new T(t);
    }
    

    Und in den Childklassen dann:

    class A2
    {
        virtual A2* clone() { return make_clone( *this ); }
    };
    

    phlox



  • phlox81 schrieb:

    würde hier dem cast ein template vorziehen:

    Hat die andere Variante mit dem Copy-Ctor Risiken oder ähnliches? Oder ist das rein stiltechnisch mit dem template?



  • SeniiX schrieb:

    phlox81 schrieb:

    würde hier dem cast ein template vorziehen:

    Hat die andere Variante mit dem Copy-Ctor Risiken oder ähnliches? Oder ist das rein stiltechnisch mit dem template?

    Generell ist es besser, wenn du den Typen zur Compilezeit kennst, ihn auch dann dort zu setzen, als wenn du zur Laufzeit dynamic_cast benutzen musst.

    Ich bin da mal drauf gekommen, weil ich nicht in jeder Clone Funktion wieder den Typen neu einsetzen wollte.
    Ich wollte das das automatisch geschieht, so ist das template dann entstanden. this kennt ja zur Compiletime seinen Typen.
    Problem kann es geben, wenn du den CopyCtor nicht public hast, aber hier hilft evtl. ein template<class T> friend T* make_clone(T& t); in der jeweiligen Klasse.

    Und natürlich sollte die Templatefunktion inline sein:

    template<class T>
    inline T* make_clone(const T& t)
    {
        return new T(t);
    }
    

    phlox



  • Die Variante mit dem Template verwendet auch einen Copy-Constructor.

    @phlox81:
    Die ptr_container Bibliothek stellt eine solche Funktion bereit, daher kommt das new_clone in diesem Beispiel überhaupt. Die Standardimplementierung ist wie bei make_clone, und sie muss für polymorphe Klassen im Sichtbarkeitsbereich jener Klasse überladen werden. In der von dieser Funktion aufgerufenen Memberfunktion wiederum auf new_clone (oder ein inhaltlich identisches Template anderen Namens) zuzugreifen wäre mir um zu viele Ecken gedacht.

    @SeniiX:
    Mir fällt grad auf dass Du in main die new_clone Funktion selbst aufrufst. Das kannst Du natürlich tun, das war aber eigentlich nicht Sinn der Sache. Boost ptr_container ruft diese Funktion selbst auf, wenn Du den Vector (mit assign) in einen anderen Vector kopierst. Deshalb hast Du mit der Standardimplementierungen bei Deinem ersten Versuch auch lauter Bs rausbekommen.



  • phlox81 schrieb:

    würde hier dem cast ein template vorziehen:

    template<class T>
    T* make_clone(const T& t)
    {
    	return new T(t);
    }
    

    Und in den Childklassen dann:

    class A2
    {
        virtual A2* clone() { return make_clone( *this ); }
    };
    

    phlox

    warum? mit der lösung mit dem virtuellen copy-konstruktor ist ein cast sowieso unnötig - und da der OP mit polymorphie arbeitet, bringt ein template auch nichts.

    (die lösung von der ich spreche ist:

    class Base
    {
    public:
       virtual ~Base () {}
       virtual Base* clone () const = 0;
    };
    
    Base* new_clone (Base const& b)
    {
       return b.clone();
    }
    
    class Derived : public Base
    {
    public:
       Derived* clone () const { return new Derived(*this); }
    };
    

    )

    /edit: wohl etwas zu langsam gewesen ^^'



  • LordJaxom schrieb:

    Die Variante mit dem Template verwendet auch einen Copy-Constructor.

    @phlox81:
    Die ptr_container Bibliothek stellt eine solche Funktion bereit, daher kommt das new_clone in diesem Beispiel überhaupt. Die Standardimplementierung ist wie bei make_clone, und sie muss für polymorphe Klassen im Sichtbarkeitsbereich jener Klasse überladen werden. In der von dieser Funktion aufgerufenen Memberfunktion wiederum auf new_clone (oder ein inhaltlich identisches Template anderen Namens) zuzugreifen wäre mir um zu viele Ecken gedacht.

    Ich kenne new_clone. Allerdings hab ich dieses Template ursprünglich nicht für ptr_container geschrieben.
    Mir gings damals darum, das ich nicht in jeder abgeleiteten Klasse die Clonemethode neu definieren musste, sondern sie per C&P übernehmen konnte.

    Wenn ich jetzt aber new_clone aufrufe, hätte ich ne endlosschleife, oder?

    class B:A
    {
      virtual A* clone()const{return new_clone(*this);}
    }
    

    Wie gesagt, ein wenig Faulheit ist da schon drin 🤡
    Man könnte natürlich genauso gut jedesmal den Klassennamen dort hinschreiben...

    phlox



  • phlox81 schrieb:

    Wenn ich jetzt aber new_clone aufrufe, hätte ich ne endlosschleife, oder?

    Da die Funktion new_clone im Namensraum der Klasse sein sollte, kann man sich da noch helfen, indem man in der Methode boost::new_clone direkt aufruft. Wenn man keine Boost-Bibliothek schreibt 😉

    Da ich aber gerade einen Vermerk im Boost-Handbuch gesehen habe, dass boost::new_clone<> wegfallen soll, sollte man damit garnicht erst anfangen.

    Vielleicht kann man da was nettes mit SFINAE basteln, meine bisherigen Versuche waren allerdings nicht so erfolgreich. Das Problem ist, die (compilezeit-statische) Bedingung zu formulieren, die darüber entscheidet, ob new T( x ) oder x.clone() aufgerufen werden sollen. (Was aber aufgrund des Aufwandes in meinen Augen eher akademischen Zwecken dient)



  • Da ich nicht extra einen neuen Thread aufmachen wollte poste ich das mal hier.
    Ich bekomme einen Fehler beim Compileren:

    expected class-name before '{' token
    

    Ich hab schon gegoogelt, allerdings steht überall nur, dass man bei diesem Fehler irgendwo vergessen hat eine Basisklasse zu inkludieren (bzw. den Header davon).
    Siehe z.B. hier: http://cplusplus.syntaxerrors.info/index.php?title=Expected_class-name_before_%E2%80%98LEFTCURLYBRACE%E2%80%99_token

    Ich habe meine Hierarchie jetzt schon so oft durchgecheckt und ich finde einfach keinen Fehler. Ich inkludiere in jeder Subclass den Header der Basisklasse und habe auch in jedem Header die Sicherung vor doppelter Inkludierung implementiert:

    #ifndef __CLASSX_HPP__
    #define __CLASSX_HPP__
    //code
    #endif //__CLASSX_HPP__
    

    Ich vermute ja, dass der Fehler darin liegt, dass ich alle Headerfiles in einem Header benötige und diese dort inkludiere. Diesen Header inkludiere ich allerdings dann wieder in jedem anderen Header, da er zentrale Deklarationen enthält. Hier meine Hierarchie im Überblick (die Implementation selbst spielt keine Rolle denke ich):

    SnmpObject.hpp (keine Vererbung):
    nur Standard-C++-Inkludes. Ist die Basisklasse für alle weiteren Klassen.

    SnmpTLV.hpp (keine Vererbung):
    Zentraler Header mit bestimmten Verarbeitungsfunktionen - nur Standard-C++-Header inkludiert.

    SnmpInteger.hpp (wird von SnmpObject vererbt):

    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    

    SnmpOctetString.hpp (wird von SnmpObject vererbt):

    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    

    SnmpNull.hpp (wird von SnmpObject vererbt):

    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    

    SnmpObjectIdentifier.hpp (wird von SnmpObject vererbt):

    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    

    SnmpSequence.hpp (wird von SnmpObject vererbt):

    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    

    SnmpUnknownObject.hpp (wird von SnmpObject vererbt):

    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    

    **
    SnmpCounter32.hpp (wird von SnmpInteger vererbt):
    SnmpCounter64.hpp (wird von SnmpInteger vererbt):
    SnmpTimeTicks.hpp (wird von SnmpInteger vererbt):
    SnmpUInteger.hpp (wird von SnmpInteger vererbt):
    **

    #include "SnmpInteger.hpp"
    #include "SnmpTLV.hpp"
    

    **
    SnmpBitString.hpp (wird von SnmpOctetString vererbt):
    SnmpIpAddress.hpp (wird von SnmpOctetString vererbt):
    SnmpNsapAddress.hpp (wird von SnmpOctetString vererbt):
    **

    #include "SnmpOctetString.hpp"
    #include "SnmpTLV.hpp"
    

    SnmpBERCodec.hpp: (keine Vererbung)

    #include "SnmpObject.hpp"
    #include "SnmpTLV.hpp"
    
    #include "SnmpInteger.hpp"
    #include "SnmpOctetString.hpp"
    #include "SnmpNull.hpp"
    #include "SnmpObjectIdentifier.hpp"
    #include "SnmpSequence.hpp"
    #include "SnmpUnknownObject.hpp"
    
    #include "SnmpCounter32.hpp"
    #include "SnmpCounter64.hpp"
    #include "SnmpTimeTicks.hpp"
    #include "SnmpUInteger.hpp"
    
    #include "SnmpBitString.hpp"
    #include "SnmpIpAddress.hpp"
    #include "SnmpNsapAddress.hpp"
    

    Wie ihr sehen könnt, ist sind die Datentypen (SnmpInteger, SnmpOctetString, etc.) im SnmpBERCodec.hpp inkludiert und die SnmpBERCodec.hpp in jedem Datentyp-Header. Führt das zum angesprochenen Fehler oder kann man das problemlos machen? 😕

    Den Fehler bekomme ich übrigens nur bei den Datentypen, die von SnmpInteger vererbt werden - ich finde aber keinen Syntax-Fehler 😞

    Need help!



  • Das sieht nach einem grossen Durcheinander und Ringincludes aus. Normalerweise kann man solche gegenseitigen Abhaengigkeiten durch forward-Deklarationen in den Headern umgehen, und die benoetigten Klassendefinitieonen dann erst in den Source-Dateien einbinden. Brauchst du die SnmpBERCodec.hpp wirklich in jedem einzelnen Header deiner anderen Klassen, oder wuerde es reichen, den Header erst in den source-Dateien deiner Klassen einzubinden? Genauso stellt sich andersrum die Frage, ob du wirklich jede einzelne Klassendefinition im header SnmpBERCodec.hpp brauchst, oder ob es dort nicht reichen wuerde, die anderen Klassen nur per forward-Deklaration bekannt zu machen. Die Vorgehensweise alles und jeden ueberall einzubinden fuehrt schnell zu einem richtigen Wartungsapltraum, mal zu schweigen von den unnoetig langen Compilezeiten, weil eine Aenderung an einem der Header gleich dazu fuehrt dass du die ganze Welt neu kompilieren musst. Zeig uns doch mal die folgenden Header, wenn du die Abhaengigkeiten nicht selbst reduzieren kannst:
    SnmpBERCodec.hpp
    SnmpInteger.hpp



  • pumuckl schrieb:

    Zeig uns doch mal die folgenden Header, wenn du die Abhaengigkeiten nicht selbst reduzieren kannst:
    SnmpBERCodec.hpp
    SnmpInteger.hpp

    Okay hier die beiden Header:

    SnmpBERCodec.hpp:

    #ifndef __SNMPBERCODEC_HPP__
    #define __SNMPBERCODEC_HPP__
    
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <cmath>
    #include <vector>
    #include <typeinfo>
    #include <sstream>
    #include <algorithm>
    
    #include <boost/ptr_container/ptr_vector.hpp>
    
    #include "SnmpObject.hpp"
    #include "SnmpTLV.hpp"
    
    //base-types of snmp
    #include "SnmpInteger.hpp"
    #include "SnmpOctetString.hpp"
    #include "SnmpNull.hpp"
    #include "SnmpObjectIdentifier.hpp"
    #include "SnmpSequence.hpp"
    #include "SnmpUnknownObject.hpp"
    
    //inherited types of snmp
    #include "SnmpCounter32.hpp"
    #include "SnmpCounter64.hpp"
    #include "SnmpTimeTicks.hpp"
    #include "SnmpUInteger.hpp"
    
    #include "SnmpBitString.hpp"
    #include "SnmpIpAddress.hpp"
    #include "SnmpNsapAddress.hpp"
    
    class SnmpBERCodec
    {
    	public:
    		//Primitive ASN.1 types with hex-ID used in SNMP
    		static const unsigned char SNMP_INTEGER = 0x02;
    		static const unsigned char SNMP_BITSTRING = 0x03;
    		static const unsigned char SNMP_OCTETSTRING = 0x04;
    		static const unsigned char SNMP_NULL = 0x05;
    		static const unsigned char SNMP_OBJECTIDENTIFIER = 0x06;
    
    		//Constructed ASN.1 types with hex-ID used in SNMP
    		static const unsigned char SNMP_SEQUENCE = 0x30;
    
    		//Primitive SNMP application types with hex-ID
    		static const unsigned char SNMP_IPADDRESS = static_cast<unsigned char>(0x40);
    		static const unsigned char SNMP_COUNTER32 = static_cast<unsigned char>(0x41);
    		static const unsigned char SNMP_GAUGE32 = static_cast<unsigned char>(0x42);
    		static const unsigned char SNMP_TIMETICKS = static_cast<unsigned char>(0x43);
    		static const unsigned char SNMP_OPAQUE = static_cast<unsigned char>(0x44);
    		static const unsigned char SNMP_NSAPADDRESS = static_cast<unsigned char>(0x45);
    		static const unsigned char SNMP_COUNTER64 = static_cast<unsigned char>(0x46);  //SNMPv2
    		static const unsigned char SNMP_UINTEGER32 = static_cast<unsigned char>(0x47); //SNMPv2
    
    		//Context-specific types within an SNMP message with hex-ID
    		static const unsigned char SNMP_GETREQUEST = static_cast<unsigned char>(0xA0);
    		static const unsigned char SNMP_GETNEXTREQUEST = static_cast<unsigned char>(0xA1);
    		static const unsigned char SNMP_GETRESPONSE = static_cast<unsigned char>(0xA2);
    		static const unsigned char SNMP_SETREQUEST = static_cast<unsigned char>(0xA3); 
    		static const unsigned char SNMP_TRAP = static_cast<unsigned char>(0xA4);
    
    		//SNMPv2
    		static const unsigned char SNMPV2P_AUTHORIZEDMESSAGE = static_cast<unsigned char>(0xA1);
    		static const unsigned char SNMPV2P_ENCRYPTEDMESSAGE = static_cast<unsigned char>(0xA1);
    		static const unsigned char SNMPV2_RESPONSE = static_cast<unsigned char>(0xA2);       
    		static const unsigned char SNMPV2P_COMMUNICATION = static_cast<unsigned char>(0xA2);
    		static const unsigned char SNMPV2_GETBULKREQUEST = static_cast<unsigned char>(0xA5);
    		static const unsigned char SNMPV2_INFORMREQUEST = static_cast<unsigned char>(0xA6);
    		static const unsigned char SNMPV2_TRAP = static_cast<unsigned char>(0xA7);
    
    		static const unsigned char SNMPV2P_ENCRYPTEDDATA = static_cast<unsigned char>(0xA1);
    
    		static const unsigned char SNMP_UNKNOWNOBJECT = static_cast<unsigned char>(0x00);
    
    		static const unsigned int IPADDRESS_LENGTH = static_cast<unsigned int>(4);
    		static const unsigned int NSAPADDRESS_LENGTH = static_cast<unsigned int>(6);
    
    		static cOcSnmpObject* extractEncoding(const cOcSnmpTLV &aTLV);
    
    		static cOcSnmpTLV extractNextTLV(const std::vector<unsigned char> &aEncode, const int &aPosition);
    		static std::vector<unsigned char> encodeLength(const int &aLength);
    
    };
    
    #endif //__SNMPBERCODEC_HPP__
    

    SnmpBERCodec.cpp:

    #include "ocSnmpBERCodec.hpp"
    
    SnmpObject* SnmpBERCodec::extractEncoding(const SnmpTLV &aTLV)
    {
    	switch(aTLV.Tag)
    	{
    		case SnmpBERCodec::SNMP_INTEGER:
    			return new SnmpInteger(aTLV.Value);
    		case SnmpBERCodec::SNMP_SEQUENCE:
    			return new SnmpSequence(aTLV.Value);
    		case SnmpBERCodec::SNMP_OBJECTIDENTIFIER:
    			return new SnmpObjectIdentifier(aTLV.Value);
    		case SnmpBERCodec::SNMP_OCTETSTRING:
    			return new SnmpOctetString(aTLV.Value);
    		case SnmpBERCodec::SNMP_BITSTRING:
    			return new SnmpBitString(aTLV.Value);
    		case SnmpBERCodec::SNMP_IPADDRESS:
    			return new SnmpIpAddress(aTLV.Value);
    		case SnmpBERCodec::SNMP_COUNTER32:
    			return new SnmpCounter32(aTLV.Value);
    		case SnmpBERCodec::SNMP_TIMETICKS:
    			return new SnmpTimeTicks(aTLV.Value);
    		case SnmpBERCodec::SNMP_NSAPADDRESS:
    			return new SnmpNsapAddress(aTLV.Value);
    		case SnmpBERCodec::SNMP_COUNTER64:
    			return new SnmpCounter64(aTLV.Value);
    		case SnmpBERCodec::SNMP_UINTEGER32:
    			return new SnmpUInteger(aTLV.Value);
    		case SnmpBERCodec::SNMP_NULL:
    			return new SnmpNull();
    		default:
    			return new SnmpUnknownObject(aTLV.Value);
    	}
    
    }
    
    SnmpTLV SnmpBERCodec::extractNextTLV(const std::vector<unsigned char> &aEncode, const int &aPosition)
    {
       //noch nicht relevant, wird daher erst später implementiert
    }
    
    std::vector<unsigned char> SnmpBERCodec::encodeLength(const int &aLength)
    {
       //noch nicht relevant, wird daher erst später implementiert
    }
    

    SnmpInteger.hpp:

    #ifndef __SNMPINTEGER_HPP__
    #define __SNMPINTEGER_HPP__
    
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <cmath>
    #include <vector>
    #include <typeinfo>
    #include <sstream>
    #include <algorithm>
    
    #include "SnmpObject.hpp"
    #include "SnmpBERCodec.hpp"
    
    class SnmpInteger : public SnmpObject
    {
    	protected:
    		unsigned long Value;
    		unsigned char BERTag;
    
    		// Returns the full BER Encoding (Type, Length, Value) of the cOcSnmpInteger Subclass
    		virtual const std::vector<unsigned char> getBEREncoding( void );
    
    	public:
    		SnmpInteger( void );
    		SnmpInteger(const unsigned long &aValue);
    		SnmpInteger(const std::vector<unsigned char> &aEncode);
    		~SnmpInteger( void ) {}
    
    		//virtual copy-ctor for cloning
    		virtual SnmpInteger* cloneObject( void ) const;
    
    		// Returns current Value
    		unsigned long getValue( void );
    
    		// Sets the Value
    		short setValue(const unsigned long &aValue);
    
    		// Extracts a Value from the BER Encoding of a Value. Called in Constructors for SnmpInteger subclass
    		short extractValueFromBEREncoding(const std::vector<unsigned char> &aEncode);
    
    		// Returns Value in string-type-form
    		virtual const std::string toString( void );
    
    		virtual bool operator==(SnmpInteger &aObject);
    		virtual bool operator!=(SnmpInteger &aObject);
    };
    
    #endif //__SNMPINTEGER_HPP__
    

    SnmpInteger.cpp:

    #include "SnmpInteger.hpp"
    
    SnmpInteger::SnmpInteger( void )
    {
    	this->Value = 0;	
    }
    
    SnmpInteger::SnmpInteger(const unsigned long &aValue)
    {
    	this->Value = aValue;
    }
    
    SnmpInteger::SnmpInteger(const std::vector<unsigned char> &aEncode)
    {
    	if( !aEncode.empty() )
    	{
    		this->extractValueFromBEREncoding(aEncode);
    	}
    }
    
    SnmpInteger* SnmpInteger::cloneObject( void ) const
    {
    	return new SnmpInteger( *this );	
    }
    
    unsigned long SnmpInteger::getValue( void )
    {
    	return static_cast<unsigned long>(this->Value);
    }
    
    short SnmpInteger::setValue(const unsigned long &aValue)
    {
    	this->Value = aValue;
    }
    
    const std::vector<unsigned char> SnmpInteger::getBEREncoding( void )
    {
    	// Databuffer
    	//char *EncodingData = const_cast<char*>(longToCharArray(this->Value));
    	std::vector<unsigned char> BEREncoding;
    	std::vector<unsigned char> EncodingData = longToCharvector(this->Value);
    
    	// Calculate encoding for length of data
    	int DataEncodingLength = EncodingData.size();
    	std::vector<unsigned char> EncodingLength = SnmpBERCodec::encodeLength(DataEncodingLength);
    	unsigned int i = 0;
    
    	// Encode T-, L-, V-Info
    	BEREncoding.push_back(this->BERTag);
    
    	for(i=0; i<EncodingLength.size(); i++)
    	{
    		BEREncoding.push_back(EncodingLength[i]);
    	}
    
    	for(i=0; i<EncodingLength.size(); i++)
    	{
    		BEREncoding.push_back(EncodingData[i]);	
    	}
    
    	return BEREncoding;
    }
    
    short SnmpInteger::extractValueFromBEREncoding(const std::vector<unsigned char> &aEncode)
    {
    		this->Value = charvectorToLong(aEncode);
    }
    
    const std::string SnmpInteger::toString( void )
    {
    	std::stringstream StringStream;
    
    	StringStream << this->Value;
    
    	if( !StringStream )
    	{
    		std::cerr << "Error occurred while conversation! (snmpinteger to string)" << std::endl;
    	}
    
    	return StringStream.str();
    }
    
    bool SnmpInteger::operator==(SnmpInteger &aObject)
    {
    	if(this->Value == aObject.getValue())
    	{
    		return true;
    	}
    
    	else
    	{
    		return false;
    	}
    }
    
    bool SnmpInteger::operator!=(SnmpInteger &aObject)
    {
    	if(this->Value != aObject.getValue())
    	{
    		return true;
    	}
    
    	else
    	{
    		return false;
    	}
    }
    

    Ich hab die cpp-Dateien auch kopiert, da es in der SnmpBERCodec.cpp sehr gut hervorkommt, dass ich in der switch-Anweisung alle Datentypen benötige.

    Danke schonmal fürs durchschauen 🙂



  • Okay, dann legen wir mal los:
    SnmpBERCodec.hpp:
    - Loesche alle #includes bis auf <vector>
    - setze vor die Klassendefinition folgende forward-Deklarationen:

    class cOcSnmpObject;
    class cOcSnmpTLV;
    

    Mehr brauchts in dem Header nicht, weil der ganze andere Kram darin nicht benutzt wird.

    SnmpBERCodec.cpp:
    - fuege #includes fuer SnmpObject und alle verwendeten Unterklassen sowie SnmpTLV hinzu

    SnmpInteger.hpp:
    - loesche alle #includes bis auf die folgenden:

    #include "SnmpObject.hpp"
    #include <vector>
    

    Rest wird nicht verwendet, und was du nicht verwendest solltest du auch nicht einbinden.

    Es faellt auf, dass du jeden Krempel, den du irgendwo mal gebraucht hast, ueberall einbindest, obwohl du ihn nichtmal ansatzweise brauchst. Wenn du spaeter/woanders im deinem Projekt an mehreren Stellen mit der ganzen Klassensammlung herumhantieren musst, die du da definiert hast, dann koenntest du zur Vereinfachung einen neuen Header anlegen, der einfach nur die ganzen SnmpXXX-header einbindet. Du solltest aber auf keinen Fall den Klienten (auch wenn du das bist) dazu zwingen, fuer etwas zu bezahlen, was er garnicht nutzt, zum Beispiel cmath, cstdio und was du da noch so alles einbindest. Zahlen tust du naemlich zumindest den Zeitaufwand, den der Compiler braucht, um die ganzen Header einzubinden, zu parsen und ggf mit zu uebersetzen, und das obwohl du nichts davon brauchst. Von grund auf alles einzubinden was dir in den Sinn kommt ist bestenfalls schlechter Stil. Ich machs meist genau andersrum: ich binde standardmaessig garnichts ein, mache fuer Klassennamen die in meinen Headern auftauchen bestenfalls forward-Deklarationen, und erst wenn der Compiler meckert dass er etwas nicht kennt, schaue ich nach mit welchem #include (oder besser, mit welcher forward-Deklaration) ich ihn mit der entsprechenden Klasse/Funktion bekannt machen kann. Im Idealfall mache ich das in zwei Schritten:

    1. kompiliere ein Programm mit leerer main(), das nur den neuen Header einbindet, so findet man raus, was unbedingt im Header bekanntgegeben werden muss.
    2. kompiliere den Source zum Header, alles was jetzt noch fehlt muss in das .cpp file, da der header ja vollstaendig ist.

    Also nochmal in kurz:
    Binde nur ein, was du wirklich brauchst, und nur genau dort, wo du es brauchst. Alles was darueber hinausgeht fuehrt zu unnoetigen Abhaengigkeiten.



  • Ich danke vielmals, werde es zukünftig beachten 🙂



  • Da ich immer noch an diesem Projekt arbeite hab ich mir gedacht, dass ich keinen neuen Thread aufmachen muss und das Thema passt eigentlich auch hier rein (boost::ptr_vector).

    Zuerst nochmal meine Vererbungshierarchie:

    SnmpObject //Basisklasse für alle weiteren Typen (mit virtuellen Funktionen)
    
    SnmpInteger //Abgeleitet von SnmpObject
    SnmpSequence //Abgeleitet von SnmpObject
    SnmpPdu //Abgeleitet von SnmpSequence
    

    Wie auf den vorigen Seiten erläutert, habe ich einen

    boost::ptr_vector<SnmpObject> _Sequence;
    

    erstellt, um einen Vector zu bekommen, der mit alle vererbten Typen gefüllt werden kann.

    Alle Typen haben eine Funktion

    const std::vector<unsigned char> cOcSnmpSequence::getBEREncoding( void )
    

    Diese Funktion ist in der Basisklasse implementiert als

    virtual const std::vector<unsigned char> getBEREncoding( void ) { }
    

    Nun will ich nacheinander diese Funktion für alle Elemente von _Sequence aufrufen.

    Prinzipiell also so:

    for(int i=0; i<_Sequence.size(); ++i)
         std::vector<unsigned char> _NextBytes = _Sequence[i].getBEREncoding();
    

    Hierbei stürzt mir das Programm jedoch immer ab. Der Fehler muss in dieser einen Zuweisung liegen, da er alles davor noch korrekt ausführt:

    std::vector<unsigned char> _NextBytes = _Sequence[i].getBEREncoding();
    

    Habe ich da einen grundsätzlichen Denkfehler oder weiß jemand Rat?
    Danke für eure Hilfe schonmal 😕


  • Mod

    SeniiX schrieb:

    Der Fehler muss in dieser einen Zuweisung liegen, da er alles davor noch korrekt ausführt:

    Das ist ein häufiger und fundamentaler Trugschluss. Der Zugriff, so wie er gezeigt wurde, ist nicht offensichtlich fehlerhaft.
    Bezeichner, die mit einem Unterstrich und einem nachfolgenden Großbuchstaben beginnen, sind in jedem Scope reserviert (könnten also z.B. Makros sein) - generell sollten Bezeichner, die mit Unterstrich beginnen, vermieden werden.



  • camper schrieb:

    Das ist ein häufiger und fundamentaler Trugschluss. Der Zugriff, so wie er gezeigt wurde, ist nicht offensichtlich fehlerhaft.
    Bezeichner, die mit einem Unterstrich und einem nachfolgenden Großbuchstaben beginnen, sind in jedem Scope reserviert (könnten also z.B. Makros sein) - generell sollten Bezeichner, die mit Unterstrich beginnen, vermieden werden.

    Naja, das mag alles so stimmen, ist auch sehr gut zu wissen für zukünftige Projekte.
    Nichtsdestotrotz funktioniert diese for-Schleife auch nicht, wenn ich die Variable ohne Unterstrich definiere:

    for(int i=0; i<Sequence.size(); i++)
        std::vector<unsigned char> NextBytes = Sequence[i].getBEREncoding();
    

    Der obige Code funktioniert genausowenig und das Programm stürzt ab 😞

    Weiß denn niemand einen Rat? 😕


Anmelden zum Antworten