Pointer und Set-Iterator



  • Hallo,

    ich möchte ein Objekt aus einem Iterator einem Pointer auf eine Klasse zuweisen.
    Bei folgendem Bsp. s.u. stürzt die exe ab.
    Ich habe schon länger rumprobiert, es geht darum dem Objekt, SNum, den Wert des Iterators zuzuweisen.

    #include <iostream>
    #include <set>
    
    using namespace std;
    
    class SNum {
    private :
    	int num;
    public:
    	SNum( int num ) { this->num = num ;};
    	~SNum(){};
    	void set_num( int num ){ this->num = num; };
        int get_num() const  { return num;};
        friend bool operator < (const SNum& a, const SNum& b) {
              if(a.get_num() < b.get_num() )
                 return true;
              else
                 return false;
           }
    };
    
    int main() {
    
    	set<SNum> sN;
    	set<SNum>::iterator sN_it;
    	SNum* s = 0;
    
    	sN.insert(SNum(2));
    	sN.insert(SNum(1));
    
    	for ( sN_it = sN.begin(); sN_it != sN.end(); ++ sN_it ) {
    		cout << sN_it->get_num()<<endl;
    		[b]*s = *sN_it;  [/b]                 <-- hier Absturz
    		cout << s->get_num()<<endl;
    	}
    	return 0;
    }
    

    vielen Dank.



  • Hallo,

    wenn ich mich nicht irre sind laut Standard Modifikationen über den Iterator eines std:set nicht erlaubt, weswegen der Dereferenzierungsoperator eine konstante Referenz zurückliefert.

    const SNum* s = 0
    

    und

    s = &*sN_it;
    

    oder am Besten gleich Referenzen benutzen:

    const SNum& s = *sN_it;
            cout << s.get_num()<<endl;
    

    Gruß,
    XSpille

    EDIT: Deine Version crashed übrigens, weil du einen Zeiger auf 0 dereferenzierst und der Zuweisungsoperator dann auf einem ungültigen Speicherbereich arbeitet.

    EDIT2: Zur Verdeutlichung:

    void operator=(const SNum& o){
    		cout << "= " << this << endl;
    		this->num = o.num;
    	}
    

    Speicheradresse 0 gehört sicherlich nicht zu deinem erlaubten Speicherbereich 😉



  • Hallo,

    vielen Dank. Dein Bsp. habe ich verstanden (hoffe ich).
    Das eigentliche Problem ist folgendes:
    Wie erhalte ich eine gültigen Zeiger zurück?
    s.u. bei beiden Funktionen wird der Zeiger als ungültig (zeigt irgendwo hin) zurückgeliefert.

    #include <iostream>
    #include <set>
    
    using namespace std;
    
    class SNum {
    private :
    	int num;
    public:
    	SNum( int num ) { this->num = num ;};
    	~SNum(){};
    	void set_num( int num ){ this->num = num; };
        int get_num() const  { return num;};
        friend bool operator < (const SNum& a, const SNum& b) {
              if(a.get_num() < b.get_num() )
                 return true;
              else
                 return false;
           }
    };
    
    void getSNum( const SNum * sn, const set<SNum> sN, int num){
    	set<SNum>::iterator sN_it = sN.find(SNum(num));
    	if ( sN_it != sN.end() )
    		sn = &*sN_it;
    }
    
    const SNum * getSNum2( const set<SNum> sN, int num){
    	set<SNum>::iterator sN_it = sN.find(SNum(num));
    	if ( sN_it != sN.end() )
    		return &*sN_it;
    	return 0;
    }
    int main() {
    
    	set<SNum> sN;
    	set<SNum>::iterator sN_it;
    	const SNum* s = 0;
    
    	sN.insert(SNum(2));
    	sN.insert(SNum(1));
    
    	s = getSNum2( sN, 2 );
    	if (s != 0 ) cout << s->get_num() << endl;
    
    	getSNum( s, sN, 2 );
    
    	if (s != 0 ) cout << s->get_num() << endl;
    
    	return 0;
    }
    


  • Woraus folgerst du, dass dein Zeiger ungültig ist?
    Also getSNum2 scheint bei mir zu funktionieren und ich sehe gerade auch keinen Grund, warum es nicht funktionieren sollte.
    Diese Variante ist auch, welche ich dir empfehlen würde.

    Aber trotzdem noch die Erläuterung, warum getSNum nicht funktioniert.
    Du übergibst einen Zeiger. Dabei wird für die Funktion eine Kopie des Zeiger erstellt. In der Funktion arbeitest du dann auf der Kopie dieses Zeigers. Nach Verlassen hast du aber wieder deinen Originalwert. Man könnte einen Zeiger auf einen Zeiger übergeben. Etwa so:

    getSNum( &s, sN, 1 );
    

    und

    void getSNum( const SNum ** sn, const set<SNum> sN, int num){ 
        set<SNum>::iterator sN_it = sN.find(SNum(num)); 
        if ( sN_it != sN.end() ) 
            *sn = &*sN_it; 
    }
    

    Aber wie erwähnt, ist der Rückgabewert aus der ersten Version (meiner Meinung nach) stilistisch schöner.

    Gruß,
    XSpille

    EDIT: btw: Benutz C++-Tags statt Code-Tags 😉



  • Hallo,

    danke für die Antwort.
    getSNum2 funktioniert leider nicht bei mir. Innerhalb der Funktion ist der Wert für s richtig, der Rückgabewert hat aber ungültige Zahlen z.B.-17891602.
    Auch habe ich getSNum umgestellt, wie von Dir beschrieben, der Wert von s ist innerhalb der Funktion gültig ausserhalb -17891602.

    void getSNum( const SNum ** sn, const set<SNum> sN, int num)
    {
    	set<SNum>::iterator sN_it = sN.find(SNum(num));
    	if ( sN_it != sN.end() )
    		*sn = &*sN_it;
    }
    

    Man sieht die falschen Werte in der Ausgabe von s.

    int main() {
    
    	set<SNum> sN;
    	set<SNum>::iterator sN_it;
    	const SNum* s = 0;
    	SNum* s2 = 0;
    	sN.insert(SNum(2));
    	sN.insert(SNum(1));
    
    	s = getSNum2( sN, 2 );
    	if (s != 0 ) cout << s->get_num() << endl;
    
    	getSNum( &s, sN, 2 );
    
    	if (s != 0 ) cout << s->get_num() << endl;
    
    	for ( sN_it = sN.begin(); sN_it != sN.end(); ++ sN_it ) {
    		cout << sN_it->get_num()<<endl;
    		s = &*sN_it;
    
    		cout << s->get_num()<<endl;
    
    	}
    	return 0;
    }
    


  • Ich war wohl gestern nicht mehr ganz wach 🙄

    Du erstellst auch eine Kopie von deinem set.
    Du musst dein set per Referenz (oder Pointer) übergeben.

    const SNum * getSNum2( const set<SNum>& sN, int num);
    

    Das gleiche gilt auch für die Funktion, die ich gepostet habe.
    Hab ich völlig übersehen, dass da kein & ist ^^

    Ansonsten wird eine Kopie erzeugt und nach dem Funktionsaufruf wieder gelöscht.
    Somit verweist der Zeiger auf ein Element eines gelöschten set.

    Gruß,
    XSpille



  • Vielen Dank!

    läuft jetzt, habe vor lauter rumprobieren, nicht mehr gesehen, dass ich den Wert übergebe.
    nochmals Danke, vor allem für die ausführlichen Erklärungen!


Anmelden zum Antworten