Komisches Verhalten von std::reverse bei Vectoren aus Objekten eigener Klasse



  • Hallo zusammen,

    mal wieder ein Problem mit meiner Klasse TSongs:

    Ich hab mal ein kleines Testprogramm geschrieben:

    int main(int argc, char* argv[])
    {
        TStrings *text = new TStringList;
        text->Text = "abc\r\ndefg\r\n\0";
    
        vector<TSong> vec;
        /*vec.push_back("48");
        vec.push_back("56");
        vec.push_back("24");
        vec.push_back("89");*/
        vec.push_back(TSong("RW", "feel", "esc", 78, text));
        vec.push_back(TSong("RaW", "feel", "esc", 78, text));
        vec.push_back(TSong("RoW", "feel", "esc", 78, text));
        vec.push_back(TSong("fcb", "feel", "esc", 78, text));
    
        delete text;
        text = NULL;
    
        cout << "Vector:" << endl;
    
        for(int i = 0; i < vec.size(); i++)
        	cout << static_cast<string>(vec[i]) << endl;
    
        cout << endl;
    
        reverse(vec.begin(), vec.end());
    
        cout << "Vector reversed:" << endl;
    
        for(int i = 0; i < vec.size(); i++)
    	cout << static_cast<string>(vec[i]) << endl;
    
        cout << endl;
    
        getch();
        return 0;
    }
    

    Der Umwandlungs-Operator von TSong für std::string ist so definiert, dass er den ersten Parameter des Konstruktors zurückgibt. Die erste ausgabe sollte also lauten:

    RW
    RaW
    RoW
    fcb

    Die zweite eben umgekehrt.

    Seltsamerweise ist die zweite Ausgabe genau so wie die erste.

    Bei einem vector<int> oder einem vector<string> gibts keine Probleme.



  • Falls es euch helfen sollte, hier die deklaration von TSong:

    #include <vcl.h>
    #include <string>
    #ifndef SongH
    #define SongH
    
    class TSong
    {
    private:
        String FArtist;
        TStrings * FText;
        String FTitle;
        String FAlbum;
        short FTrackNo;
    protected:
    public:
    	TSong()
        {
        	FArtist = "";
            FText = new TStringList;
            FTitle = "";
            FAlbum = "";
            FTrackNo = -1;
        }
    
    	TSong(const TSong &source)
        {
        	Text = new TStringList;
        	FArtist = source.FArtist;
            FText->Assign(source.FText);
            FTitle = source.FTitle;
            FAlbum = source.FAlbum;
            FTrackNo = source.FTrackNo;
        }
    
        TSong(String AArtist, String ATitle, String AAlbum, short ATrackNo, TStrings * AText);
    
        virtual ~TSong()
        {
        	delete FText;
        }
    
        const TSong &operator=(const TSong &source)
        {
            if(this == &source)
            	return *this;
    
            TSong temp(source);
            TStrings *pText = FText;
            FText = temp.FText;
            temp.FText = pText;
        	return *this;
        }
    
        friend const bool operator <(const TSong &left, const TSong &right);
    	friend const bool operator <=(const TSong &left, const TSong &right);
    	friend const bool operator >(const TSong &left, const TSong &right);
    	friend const bool operator >=(const TSong &left, const TSong &right);
    	friend const bool operator ==(const TSong &left, const TSong &right);
        __property String Artist = { read = FArtist, write = FArtist };
        __property TStrings * Text = { read = FText, write = FText };
        __property String Title = { read = FTitle, write = FTitle };
        __property String Album = { read = FAlbum, write = FAlbum };
        __property short TrackNo = { read = FTrackNo, write = FTrackNo };
    
        operator std::string()
        {
        	return Artist.c_str();
        }
    };
    //---------------------------------------------------------------------------
    const bool operator ==(const TSong &left, const TSong &right)
    {
    	return (left.FArtist == right.FArtist && left.FTitle == right.FTitle);
    }
    //---------------------------------------------------------------------------
    const bool operator <(const TSong &left, const TSong &right)
    {
    	return ((left.FArtist < right.FArtist) || (left.FArtist == right.FArtist && left.FTitle < right.FTitle));
    }
    //---------------------------------------------------------------------------
    const bool operator <=(const TSong &left, const TSong &right)
    {
    	return left < right || left == right;
    }
    //---------------------------------------------------------------------------
    const bool operator >(const TSong &left, const TSong &right)
    {
    	return right < left;
    }
    //---------------------------------------------------------------------------
    const bool operator >=(const TSong &left, const TSong &right)
    {
    	return right <= left;
    }
    //---------------------------------------------------------------------------
    #endif
    


  • sieh dir einmal den operator = an.
    du änderst eigentlich nur FText die anderen membervariablen werden nicht geändert.
    er sollte wahrscheinlic so aussehen( ohne zu wissen wie TStringList funktioniert)

    const TSong &operator=(const TSong &source)
        {
            if(this == &source)
                return *this;
            delete FText;
            FArtist = source.FArtist;
            FText = new TStringList;
            FText->Assign(source.FText);
            FTitle = source.FTitle;
            FAlbum = source.FAlbum;
            FTrackNo = source.FTrackNo;
    
            return *this;
        }
    

    ausserddem sollte es wahrscheinlich heissen:

    TSong(const TSong &source)
        {
            FText = new TStringList; // nicht Text=new TStringList;
            FArtist = source.FArtist;
            FText->Assign(source.FText);
            FTitle = source.FTitle;
            FAlbum = source.FAlbum;
            FTrackNo = source.FTrackNo;
        }
    

    Kurt



  • 1.: Danke, das wars!
    Das passiert wenn man mal bei der Implementierung eines Operators nicht aufpasst...

    Zum Zweiten: Geht beides (wegen der Borland-properties), aber FText ist natürlich konsequenter.

    Edit: Nochmal zum operator=:

    Das new TStringList ist überflüssig, weil das schon im Ctor aufgerufen wird.



  • Eßer schrieb:

    Das new TStringList ist überflüssig, weil das schon im Ctor aufgerufen wird.

    Da ich nicht weiss wie diese TStringList arbeitet habe ich

    delete FText;  // alte liste löschen da sonst memleak
       FArtist = source.FArtist;
       FText = new TStringList;// neue liste anlegen
    

    geschrieben da ich annehme dass ohne delete dadurch die alten daten nicht freigegeben werden. Wann aber TStringList::Assign() die alten daten löchscht dann kannst du dir delete FText; und FText=new TStringList; natürlich sparen.
    Kurt.


Anmelden zum Antworten