Vektor mit Pointern ... alles eine Adresse?



  • Hallo liebes Forum,
    ich habe folgendes Problem:
    ich habe eine Klasse clBaseObject:

    class clBaseObject
    {
    public:
                     clBaseObject();
        virtual     ~clBaseObject();
    
        virtual void PrintProperties();
    };
    

    dazu habe ich eine Klasse clCase:

    class clCase
    {
    public:
                    clCase();
        virtual    ~clCase();
    
        void        AddObject(clBaseObject*);
        void	SeeContents();
    
    private:
        vector<clBaseObject*> m_aObjects;
    
    };
    

    , welche (wie man sieht) in einem Vektor diese clBaseObjects als Pointer speichern soll.
    Wenn ich jetzt mit einer Funktion AddObject:

    void clCase::AddObject(clBaseObject* pBaseObject)				 {	
        m_aObjects.push_back(pBaseObject);
    
        return;
    }
    

    die Sachen in den Vektor hauen möchte, dann bekommen alle Elemente des Vektors die gleiche Adresse. Wie kann das sein, was mache ich falsch?
    Meine Main-Fkt. sieht wie folgt aus:

    int main() 
    {
    	std::cout << "Welcome to the photo equipment simulator!" << endl;
    	std::cout << endl;
    
    	clCase*			pCase		= new clCase();
    	clCamera*		pCamera		= NULL;
    	clFilm*			pFilm		= NULL;
    	clObjective*	pObjective	= NULL;
    	clFlashlight*	pFlashlight = NULL;
    
    	char			cChoice;
    	bool			bQuit = false;
    
    	while (!bQuit) {
    		cChoice = cMenu();
    
    		switch (cChoice) {
    		case 'a':
    			pCamera = new clCamera();
    			pCase->AddObject(pCamera);
    			delete pCamera;
    			break;
    
    		case 'b':
    			pObjective = new clObjective();
    			pCase->AddObject(pObjective);
    			delete pObjective;
    			break;
    
    		case 'c':
    			pFilm = new clFilm();
    			pCase->AddObject(pFilm);
    			delete pFilm;
    			break;
    
    		case 'd':
    			pFlashlight = new clFlashlight();
    			pCase->AddObject(pFlashlight);
    			delete pFlashlight;
    			break;
    
    		case 'e':
    			pCase->SeeContents();
    			break;
    
    		case 'x':
    			bQuit = true;
    			break;
    
    		default:
    			std::cout << "Wrong input. Please try again." << endl << endl;
    			break;
    
    		} // end switch (cChoice)
    	} // end while (!bQuit)
    
    	delete pFilm;
    	delete pObjective;
    	delete pFlashlight;
    	delete pCamera;
    	delete pCase;
    
    	system("PAUSE");
    	return 0;
    }
    


  • Du darfst das Objekt nicht löschen, nachdem du es hinzugefügt hast. Warum arbeitest du überhaupt mit sovielen rohen Zeigern? Vielleicht solltest du dir mal "Smart Pointer" ansehen.



  • Da Du deine Objekte stets sofort wieder löschst, wird das jeweils nächste halt an der selben, gerade wieder freigewordenen, Adresse angelegt. Klingt doch ökonomisch.
    Wenn Du deine Objekte jedoch noch mal wiedersehen willst, darfst Du sie erst löschen, wenn Du sie nicht mehr brauchst. Logisch?



  • pCamera = new clCamera(); 
                 pCase->AddObject(pCamera); 
                 delete pCamera;
    

    Der Code baut eine Kamera, tut den Pointer darauf in den Vektor und löscht dann die Kamera. Die Folge ist, dass im Vektor ein Pointer auf ein totes Objekt liegt. Das wolltest du bestimmt nicht.

    Entweder du packst Objekte in den Vektor, oder du bleibst bei Pointern und löscht ihm die Objekte, auf die die Pointer zeigen, nicht weg.

    Von welcher Adresse redest du eigentlich? Möglicherweise von der Adresse von pCamera, pFilm, pWasauchimmer? Das liegt wohl daran, dass der Speicher für die alte Kamera freigegeben wurde und wenn du neuen anforderst gibt er dir genau denselben Speicher wieder, da er ja nicht mehr benutzt wird.

    ... zu spät -.-



  • Ich meinte die Adressen von den Elementen, aber die Antworten waren schon richtig, danke - habt Recht gehabt, dadurch gab's dann Zugriffsverletzungen etc. pp. ... den Speicher gebe ich am Besten zum Ende der main-Funktion hin frei, richtig?



  • daddy_felix schrieb:

    Du darfst das Objekt nicht löschen, nachdem du es hinzugefügt hast. Warum arbeitest du überhaupt mit sovielen rohen Zeigern? Vielleicht solltest du dir mal "Smart Pointer" ansehen.

    Einfache Übung - ich habs scheinbar bis heute nich begriffen, wie man mit Zeigern umgeht 😃



  • Und im Übrigen ist Ungarische Notation völlig nutzlos.



  • Laszló schrieb:

    Und im Übrigen ist Ungarische Notation völlig nutzlos.

    Ansichts- und Übersichtssache. Ich mag sie.


  • Mod

    taiBsu schrieb:

    Ansichts- und Übersichtssache. Ich mag sie.

    Es gibt starke, objektive Argumente dagegen (siehe zahlreiche Threads hier im Forum), sie in Sprachen mit starker Abstraktion (C++, Java und ähnliches) zu benutzen. Du wirst dich noch ärgern, wenn du sie weiter benutzt und nur geringen Nutzen (eher Schaden) daraus ziehen.



  • SeppJ schrieb:

    taiBsu schrieb:

    Ansichts- und Übersichtssache. Ich mag sie.

    Es gibt starke, objektive Argumente dagegen (siehe zahlreiche Threads hier im Forum), sie in Sprachen mit starker Abstraktion (C++, Java und ähnliches) zu benutzen. Du wirst dich noch ärgern, wenn du sie weiter benutzt und nur geringen Nutzen (eher Schaden) daraus ziehen.

    da werd ich mich mal belesen. Ich bin auch nur Student im 1. Sem und lerne von meinem Chef 😉 Aber bis jetzt empfand ich sie immer als sehr übersichtlich.



  • taiBsu schrieb:

    da werd ich mich mal belesen. Ich bin auch nur Student im 1. Sem und lerne von meinem Chef 😉 Aber bis jetzt empfand ich sie immer als sehr übersichtlich.

    Ich möchte nicht böse klingen: Aber häufig sind es gerade die alten Entwickler die sich auf eine besondere Vorgehensweise festgefahren haben. Wenn du die UN umbedingt nutzen willst, so gebe ich dir aber den ganz starken rat die Anzahl der Präfixe auf ein Minimum zu reduzieren (z.B. p für Zeiger, n für alle Ganzzahlen...). Und spätestens bei Klassen sollte man dies gänzlich unterlassen, sonst müsstest du irgendwann eine riesige Tabelle mit Präfixen führen.

    Jede moderne IDE nennt dir den Typ einer Variable in der Regel wenn du z.B. mit dem Mauszeiger (oder was auch immer) eine kurze Zeit darüber verharrst. OO-Sprachen führen so viele Typen ein, das man die UN gar nicht konsequent umsetzen kann (zumal sie von vielen ohnehin zu extrem umgesetzt wurde).

    Ja, auch ich hatte eine Zeitlang viel von der UN gehalten, aber das änderte sich recht schnell nachdem man effektiv eine zweite Sprache für die Präfixe lernen musste. Zudem macht sie den Code auch nicht wirklich lesbar und führt gerne auch zu kryptischen Abkürzungen (zumindest war dies meine Erfahrung mit Programmierern die UN eingesetzt haben).

    Was glaubst du ist für einen Projektneuling aus dem Stegreif besser zu verstehen: "anzahlStudenten" oder "nStudenten"? (Wobei das noch gut ist, ich kenne Entwickler die dann eher nStd oder ähnliches unverständliches/mehrdeutiges schreiben würden).

    Wenn du "anzahlStudenten" ließt, ohne den Typ zu kennen: Was nimmst du an (Ich würde unter einer Anzahl von Studenten auch ohne den Typ zu kennen jedenfalls weder einen String noch eine Gleitkommazahl erwarten) - reicht die Bezeichnung wirklich nicht um den Sinn zu verstehen?

    Wie häufig wird wohl eine Codestelle geändert, gegenüber gelesen? (Falls letzteres wesentlich höher ist, was in der Regel auch gilt, ist ein lesbarer Code wesentlich wichtiger, als eine exakte Typinformation).



  • asc schrieb:

    taiBsu schrieb:

    da werd ich mich mal belesen. Ich bin auch nur Student im 1. Sem und lerne von meinem Chef 😉 Aber bis jetzt empfand ich sie immer als sehr übersichtlich.

    Ich möchte nicht böse klingen: Aber häufig sind es gerade die alten Entwickler die sich auf eine besondere Vorgehensweise festgefahren haben. Wenn du die UN umbedingt nutzen willst, so gebe ich dir aber den ganz starken rat die Anzahl der Präfixe auf ein Minimum zu reduzieren (z.B. p für Zeiger, n für alle Ganzzahlen...). Und spätestens bei Klassen sollte man dies gänzlich unterlassen, sonst müsstest du irgendwann eine riesige Tabelle mit Präfixen führen.

    Jede moderne IDE nennt dir den Typ einer Variable in der Regel wenn du z.B. mit dem Mauszeiger (oder was auch immer) eine kurze Zeit darüber verharrst. OO-Sprachen führen so viele Typen ein, das man die UN gar nicht konsequent umsetzen kann (zumal sie von vielen ohnehin zu extrem umgesetzt wurde).

    Ja, auch ich hatte eine Zeitlang viel von der UN gehalten, aber das änderte sich recht schnell nachdem man effektiv eine zweite Sprache für die Präfixe lernen musste. Zudem macht sie den Code auch nicht wirklich lesbar und führt gerne auch zu kryptischen Abkürzungen (zumindest war dies meine Erfahrung mit Programmierern die UN eingesetzt haben).

    Was glaubst du ist für einen Projektneuling aus dem Stegreif besser zu verstehen: "anzahlStudenten" oder "nStudenten"? (Wobei das noch gut ist, ich kenne Entwickler die dann eher nStd oder ähnliches unverständliches/mehrdeutiges schreiben würden).

    Wenn du "anzahlStudenten" ließt, ohne den Typ zu kennen: Was nimmst du an (Ich würde unter einer Anzahl von Studenten auch ohne den Typ zu kennen jedenfalls weder einen String noch eine Gleitkommazahl erwarten) - reicht die Bezeichnung wirklich nicht um den Sinn zu verstehen?

    Wie häufig wird wohl eine Codestelle geändert, gegenüber gelesen? (Falls letzteres wesentlich höher ist, was in der Regel auch gilt, ist ein lesbarer Code wesentlich wichtiger, als eine exakte Typinformation).

    Natürlich hast du Recht, übertreiben würde ich es auch nicht mit der UN, aber es ist doch sehr hilfreich, bspw. Klassen einfach mit cl zu "präfixieren" ( 😃 ), Chars mit c, Integers mit i, vor allem Pointer mit p usw., würde aber nie auf die Idee kommen, bspw. bei einem Vektor mit Zeigern auf Integer apiVektor zu benutzen oder so... bei mehr als 2 Präfixbuchstaben hörts dann auf 😉 Manche Variablendatentypen sind einfach nicht durch einfachen Kontext zu erkennen und wenn man den Code nur kurz überfliegt, möchte man sicher nicht alle 20 Zeichen mit der Maus für 2 Sekunden stehen bleiben. 🤡
    Wie macht ihr's denn? Einfach alles klein, oder Klassen und Funktionen groß,...?!



  • taiBsu schrieb:

    Natürlich hast du Recht, übertreiben würde ich es auch nicht mit der UN, aber es ist doch sehr hilfreich, bspw. Klassen einfach mit cl zu "präfixieren" ( 😃 ), Chars mit c, Integers mit i, vor allem Pointer mit p usw.,

    Warum ist es hilfreich? Ich sehe hier bereits keinen Sinn.

    taiBsu schrieb:

    Manche Variablendatentypen sind einfach nicht durch einfachen Kontext zu erkennen und wenn man den Code nur kurz überfliegt, möchte man sicher nicht alle 20 Zeichen mit der Maus für 2 Sekunden stehen bleiben.

    Braucht man zum Verstehen von Code in der Regel nur selten den Datentyp (Wenn du ihn wirklich benötigst, dürfte deine Benennung schon allgemein recht schlecht sein). Wichtig wird der Typ eigentlich erst wenn man etwas ändert, und selbst da kann man häufig ohne ein Präfix den Wert direkt erkennen, oder mal die Sekunde warten.

    taiBsu schrieb:

    Wie macht ihr's denn? Einfach alles klein, oder Klassen und Funktionen groß,...?!

    1. Mengenmäßig möglichst kleine leicht verständliche Einheiten.
    2. An den Bezeichnern sollte die grobe Funktion ablesbar sein, falls sinnvoll enthält diese tatsächlich so etwas wie Typbezeichner ("anzahlStudenten", "adressliste"...).
    3. Es gibt keine Standardisierte Schreibweise, ich verwende im wesentlichen die Notation die auch in C# gebräuchlich ist (und die ich auch schon vor C# kannte): Typen (Klassen...) und Methoden Pascal Case, Variablen Camel Case, eigentlich keine Präfixe*, außer unter C# und da nur "I" für Interfaces.

    * Beruflich stimmt diese Aussage nicht ganz, mein Chef will zumindest für Membervariablen ein Präfix, wobei er sich vom unter C++ absolut unüblichen "F" gelöst, und statt dessen nun "m_" akzeptiert hat. Ebenso gibt es bei uns drei Typpräfixe: E für Enums, C für Standard C++ Klassen, T für von TObject abgeleitete Klassen (VCL/C++ Builder - diese verhalten sich etwas Anders).

    Wenn man den Sinn eines Codes nur durch Typpräfixe versteht, hat man irgendetwas grundlegend falsch gemacht.



  • Ich habe mich auf ein m_ für Klassenmember breit schlagen lassen. Ansonsten gibt es keine Typpräfixe oder -suffixe. Die ursprüngliche Idee der UN war ja gerade nicht den technischen Typ zu spezifizieren ("systems HN") sondern den fachlichen Typ ("applications HN"). Das wurde dann aber gründlich missachtet und heute müssen Legionen von Entwicklern den Code warten.

    Mein Einfachbeispiel gegen SystemsHN sind typedefs. Was nimmt man dann? präfix t, tcl, tm, tc, tp, te, ttcl, ...



  • Laszló schrieb:

    Die ursprüngliche Idee der UN war ja gerade nicht den technischen Typ zu spezifizieren ("systems HN") sondern den fachlichen Typ ("applications HN").

    Von der Theorie wie etwas geplant wurde, bis zur Realität wie etwas dann verwendet wird, fällt nicht selten etwas unter den Tisch. Aber heutzutage würde ich auch hier eher zu Namespaces greifen, als Präfixe zu verwenden.

    Laszló schrieb:

    Mein Einfachbeispiel gegen SystemsHN sind typedefs.

    Meins sind Templates. Spätestens da kann je nach dem wie das Template aufgebaut ist eh keine Typangabe mehr erfolgen...



  • asc schrieb:

    Laszló schrieb:
    Mein Einfachbeispiel gegen SystemsHN sind typedefs.

    Meins sind Templates. Spätestens da kann je nach dem wie das Template aufgebaut ist eh keine Typangabe mehr erfolgen...

    Das mit den typedefs funktioniert auch bei C 😃 Aber templates sind in dem Fall vielleicht noch etwas anschaulicher 👍


Log in to reply