C++ Referenzen und Kopien davon

  • Ersteller Ersteller Furtano
  • Erstellt am Erstellt am
F

Furtano

Gast
Hallo,

ich schreibe eine Ameisensimulation. Dabei möchte ich die verschiedenen Entwicklungsstadien der Ameise simulieren.
Egg -> Grub -> Puppet -> Imago

Ich generiere alle 3 Tage neue Eier, die dann altern.
Wenn ein Ei alt genug ist, soll es zur Grub (Larve) werden.

Leider funktioniert mein Code so nicht, er generiert zwar alle 3 Tage Eier, aber wenn es soweit ist dass Larven erzeugt werden sollen werden keine angezeigt. :(

Hängt das mit der Zeile 49 (zweiter Code) zusammen?

Danke !


PHP:
std::vector  <Breed*> breed;
std::vector  <Breed*> tempBreed;

void antQueen(){
	do {

		tempdays = timeSimulationRuned.getElapsedTime().asSeconds();
		tempdays = (float)((int)(tempdays*100))/100;

		// 1 new day:
		if (fmod(tempdays, 1) == 0 ){	

			// !first round
			if (oldTempDays != tempdays){
				std::cout << "\n\n\n\n\n MODODODO" << breed.size() <<  "\n\n\n";

				// A new Ant Spawns in The Game ;)
				init.lifeStadium[livingAnts] = 1;
				livingAnts++;

				// Queen spawns an Egg 
				if (days % 3 == 0 && days != 0){
					std::cout << "\n 1EGGGGGGGGGGGGGGGGGGGG";
					Egg egg;
					egg.days = 0;
					egg.lifeStatus = true;
					breed.push_back(&egg);
					std::cout << "EGGTIME\n";

					
				}

				// For Stats
				checkBreed();
				// 1 Day is Over
				days++;
				for (Breed * ant : breed){
					ant->days++;
				}

			}
			// For Twice-Failure Checking
			oldTempDays = tempdays;
		}

	}
	while (true);
}

PHP:
void checkBreed(){

	
	eggs = 0;
	grubs = 0;
	puppets = 0;

	for (Breed* ant : breed){
		

		if(ant->status == status_EGG){
			// Egg is developed ready
                        // endDate == 14
			if (ant->days == ant->endDate){
				eggs--;
				

				Grub grub;
				grub.days = 15;
				grub.lifeStatus = true;
				grub.status = status_GRUB;
				tempBreed.push_back(&grub);


			}
			else {
				eggs++;
			}

		}
		else if (ant->status == status_GRUB){
			std::cout << "\n\nGRUBBB";
			grubs++;
		}
		else if (ant->status == status_PUPPET){
			puppets++;
		}

		// Is an Ant !!!
		else {

		}

		
	}

	for (Breed * tempAnt : tempBreed){
		std::cout << "\n\nHAHAHHA GRUBBBBY";
		breed.push_back(tempAnt);
		grubs++;
	}

	if (days % 30 == 0 && days != 0){
		days = 0;
		months++;
	}

	if (months % 12 == 0 && months != 0){
		months = 0;
		years++;
	}
}

PHP:
class Breed {

	public:		
		Breed();
		statusOfAnt status;
		int days;
		int endDate;
		int food;
		// 0 == Dead, 1 == Alive 
		bool lifeStatus;
		int aviableFood;

		void feed(int food);
		void dayIsOver();

};

class Egg : public Breed {

public:

	Egg (){
		status = status_EGG;
		days = 0;
		endDate = 5;
		food = 10;
		lifeStatus = 0;
	}
	//this.status = status_PUPPET;
	
	void Egg::dayIsOver(){
		// Egg doesnt need food
		this->food -= 0;
	}
};


class Grub : public Breed {

public:

	Grub (){
		status = status_GRUB;
		days = 0;
		endDate = 24;
		food = 2;
		lifeStatus = 0;
	}

	
	void Grub::dayIsOver(){
		this->food -= 3;
	}
	//this.status = status_PUPPET;

};
 
Zuletzt bearbeitet von einem Moderator:
Zeile 27 in Code 1 erzeugt einen Zeiger auf eine Temporäre => du lebst im Undefined Behaviour Land => warum crasht das bei dir bitte nicht?
In deiner Variable "breed" stehen daher nur Zeiger auf nicht mehr existente Objekte => jeder Zugriff auf die Elemente in "breed" ist somit ungültig!
 
Zuletzt bearbeitet:
Das soll nicht gehen?
PHP:
// egg undefined ???
Egg egg;
egg.days = 0;
egg.lifeStatus = true;
// fehler???
breed.push_back(&egg);

Den Zeiger haben wir gemacht wegen Objekt-Slicing, wie geht es anders? Die Objekte so in die Liste zu legen geht ja nicht.
 
Zuletzt bearbeitet von einem Moderator:
Das kann nicht gehen, da du in "breed" die Adresse von "egg" speicherst. Der Zeiger wird in dem Moment ungültig, in dem du den Block in dem "egg" definiert ist verlässt.
Code:
if (days % 3 == 0 && days != 0){
  std::cout << "\n 1EGGGGGGGGGGGGGGGGGGGG";
  Egg egg;
  egg.days = 0;
  egg.lifeStatus = true;
  breed.push_back(&egg);
  std::cout << "EGGTIME\n";
}//ab hier ist "egg" nicht mehr auf dem Stack => Zeiger in "breed" zeigt also auf ungültigen Speicherbereich!

Du musst das ganze Objekt auf den Heap legen, am besten mit einem Smartpointer, denn sonst musst du dich auch noch manuell um die Speicherverwaltung kümmern, und das macht man in modernen C++ auf keinen Fall.
 
Code:
if (days % 3 == 0 && days != 0){
    std::cout << "\n 1EGGGGGGGGGGGGGGGGGGGG";
    Egg egg;
    egg.days = 0;
    egg.lifeStatus = true;
    breed.push_back(&egg);
    std::cout << "EGGTIME\n"; 
}

Das geht deshalb nicht, weil dieses Egg-Objekt auf dem Stack angelegt wurde und somit zerstört wird, so bald der Code-Bereich in den umgebenden geschweiften Klammern (also der if-Block) verlassen wird. Danach enthält dein vector also einen Pointer, der auf ein nicht mehr existierendes Egg-Objekt zeigt.
 
Also so? Kommt es dann nicht zum Objekt-Slicing?
Ergänzung ()

@QDOS wie lege ich das Objekt auf einen Heap (erst mal ohne Smart Pointer)? Sie müssen ja dann global sichtbar sein.

// Habe eben mich zu Polymorphismus informiert, jedoch weiß ich jetzt immer noch nicht wie ich das Problem löse mit diesen ominösen Heap?

// ah jetzt geht mir ein Licht auf, der Heap ist unabhängig von den Blöcken im Programm, ich kann also sowas machen, ja ?


PHP:
void bla (){
   //innerhalb dieser kleinen Funktion reserviert auf dem Heap ?
    int * blub = new blub[3];
}

void blubAufruf(){
  // Aufruf der Variablen aus dem Heap
   std::cout << blub[0];
}
:)
Ergänzung ()

Benötige ich SmartPointer wirklich für sowas "kleines"?
Könnte doch theoretisch beim schließen der Applikation alle Objekte im Speicher löschen.
Dauert ja bis ich mich da auch noch einarbeite. :(
 
Zuletzt bearbeitet von einem Moderator:
Furtano schrieb:
Ergänzung ()

Benötige ich SmartPointer wirklich für sowas "kleines"?
Wenn du nicht durch umfangreiches Profiling beweisen kannst dass sich ein SmartPointer negativ auf die Performance auswirkt - sollte gerade bei std::unique_ptr nicht der Fall sein - würde ich dir raten für sowas IMMER SmartPointer zu verwenden.

Furtano schrieb:
Könnte doch theoretisch beim schließen der Applikation alle Objekte im Speicher löschen.
Nur wirst du es in umfangreichen Anwendungen nicht schaffen alle Enden des Programmes zu finden => SmartPointer gibt den Speicher aber in jedem Fall frei. Außerdem: was machst du wenn du zwischenzeitlich schon mal Objekte freigeben musst, da zB deine Ameisen sterben? Manuelles Speichermanagement? Die Sprache heißt C++ und nicht C!
 
Ok ich möchte std::auto_ptr aus <memory> verwenden.
Wie lege ich jetzt diesen Pointer/Objekt
PHP:
breed.push_back(new Egg);

auf dem Heap an, mit SmartPointer ?
 
Zuletzt bearbeitet von einem Moderator:
Nicht auto_ptr verwenden! Der ist wegen seiner seltsamen Kopiersemantik (machst du von einem auto_ptr eine Kopie, wird das Original ungültig gemacht) veraltet. Verwende stattdessen std::unique_ptr.

Und dadurch, daß du dein Breed-Object mit new angelegt hast, liegt das Ding bereits auf dem Heap (oder technisch korrekt "free store" ... Heap ist eine C-Bezeichnung).

Code:
std::unique_ptr< Egg > egg( new Egg );

Dann aber bei der weiteren Verwendung darauf achten, daß std::unique_ptr nicht kopierbar sondern nur "moveable" sind. Wenn du einen unique_ptr in einen vector stecken willst, geht das nur mit std::move().

Code:
std::vector< std::unique_ptr< Egg > > myVector;
std::unique_ptr< Egg > egg( new Egg );

myVector.push_back( std::move( egg ) ); // <- Hiernach ist der "egg"-Pointer selbst leer.

Mann kann allerdings auch über emplace_back() den unique_ptr quasi on-the-fly direkt im vector erzeugen.

Code:
std::vector< std::unique_ptr< Egg > > myVector;
myVector.emplace_back( new Egg );
 
Zuletzt bearbeitet:
Zurück
Oben