Προς το περιεχόμενο

C++ inheritance - vector list - delete variables


Προτεινόμενες αναρτήσεις

Δημοσ.

Γειά σας έχω το εξής πρόβλημα. Θέλω να φτιάξω κάποια αντικείμενα σε μια λίστα με την βοήθεια της κληρονομικότητας και μετά να κάνω μια λούπα και να τρέξω τις κοινές μεθόδους τους.

 

>
#include <iostream>
#include <vector>

class Animal
{
public:
virtual void makeSound();
};

void Animal::makeSound()
{
std::cout << "makes a sound" << std::endl;
}

class Cat : public Animal
{
public:
virtual void makeSound();
};

void Cat::makeSound()
{
std::cout << "cat ";
this->Animal::makeSound();
}

class Bird : public Animal
{
public:
virtual void makeSound();
};

void Bird::makeSound()
{
std::cout << "bird ";
this->Animal::makeSound();
}

int main (int argc, const char * argv[])
{

Cat* cat = new Cat;
Bird* bird = new Bird;

//cat->makeSound(); // OK
//bird->makeSound(); // OK

std::vector<Animal*> animalList;

animalList.push_back(cat);
animalList.push_back(bird);

std::vector<Animal*>::iterator animalIter;

for (animalIter = animalList.begin(); animalIter < animalList.end(); animalIter++)
{
   	(*animalIter)->makeSound(); // ΟΚ
}

return 0;
}


 

Ας πούμε ότι φτιάχνω ένα αντικείμενο cat, κάνω κάποιες εκκινήσεις στις ιδιότητες του αντικειμένου και μετά την καταχωρώ στην vector λίστα. Να σημειωθεί ότι αυτή η κατασκευή αντικειμένου γίνεται μέσα σε μια μέθοδο και υποτίθεται ότι, ότι μεταβλητή δημιουργείται μέσα σε μέθοδο είναι ενεργή μόνο μέσα στην μέθοδο την οποία δηλώθηκε, οπότε λέω εγώ θεωρητικά πως δεν το πειράζω διότι ο compiler θα το κανονίσει στο παρασκήνιο.

 

Στην ουσία θα κρατήσω μόνο objects μέσα στην λίστα vector.

 

Ποιά είναι η γνώμη σας στο θέμα καταστροφής αντικειμένων σε αυτή την περίπτωση;

Ευχαριστώ για τον χρόνο σας και την βοήθεια σας. :rolleyes:

Δημοσ.

Δεν είναι τόσο σαφής η ερώτησή σου είναι η αλήθεια. Πάντως, στο παράδειγμα που έχεις υπάρχει memory leak. Πρέπει στο τέλος να διατρέξεις πάλι το vector και να κάνεις delete τους pointers.

 

Γράφεις: "υποτίθεται ότι, ότι μεταβλητή δημιουργείται μέσα σε μέθοδο είναι ενεργή μόνο μέσα στην μέθοδο την οποία δηλώθηκε". Αυτό είναι μερικώς λάθος. Οτιδήποτε είναι dynamicaly allocated (όπως στο παράδειγμά σου οι cat και bird) δεν καθαρίζεται μόνο του.

Δημοσ.

Πρώτον όπως είπε το παπί, κλάσεις οι οποίες προορίζονται για πολυμορφική χρήση (δηλαδή όποιες έχουν έστω και μία virtual function) πρέπει να έχουν και virtual destructor.

 

Στη συνέχεια: δε μπορώ να καταλάβω ακριβώς τι εννοείς, αλλά αυτό που φαντάζομαι είναι ότι μιλάμε για το σενάριο "έχω μια local μεταβλητή σε μια μέθοδο, τη βάζω μέσα σε vector και επιστρέφω το vector". Σ' αυτή την περίπτωση βάζεις μέσα ένα αντίγραφο της μεταβλητής (και όχι την ίδια την τιμή της, γιατί αυτή θα πάψει να υφίσταται μόλις η μέθοδος επιστρέψει -- κλασσική παγίδα στη C++ που μπορεί να συμβεί σε διάφορες παραλλαγές). Να έχεις υπόψη ότι δεν γίνεται να χρησιμοποιήσεις vector απο πολυμορφικά αντικείμενα εξαιτίας του slicing, και πρέπει αντί γι' αυτό να έχεις vector από pointers όπως στον κώδικα που δίνεις.

 

Τέλος, όπως είπε ο godlike το πρόγραμμά σου ως έχει τεχνικά εμφανίζει memory leak αλλά στην προκειμένη περίπτωση το θεωρώ αρκετά πιθανό να το ξέρεις και να μη σε ενδιαφέρει γιατί δεν παίζει κανένα απολύτως ρόλο (και γω το ίδιο θα έκανα σε ένα τόσο μικρό test program). Παρόλα αυτά καλό είναι που το αναφέρουμε για να είμαστε σίγουροι.

Δημοσ.

Ακολουθεί το φλέγον κομμάτι σε C#

 

Όπως βλέπετε:

  • Πάω να φτιάξω 100 αντικείμενα της κλάσης Cat και να τα τοποθετήσω στην λίστα.
  • Ο λόγος που γίνεται η δημιουργία του αντικειμένου γάτας είναι για να μπορώ να κάνω εκκίνηση κάποιες τιμές του αντικειμένου.
  • Αυτομάτως κατά την έξοδο από την λούπα for το αντικείμενο cat παύει να υφίσταται διότι ο garbage collector αναλαμβάνει να το διαγράψει.
  • Όμως η λίστα θα παραμείνει καθ' όλη την διάρκεια εκτέλεσης του προγράμματος διότι είναι μια ιδιότητα της κλάσεως κατά την οποία δηλώθηκε.

>
public void Initialize()
	{
		animalList = new List<Animal>();
		
		for (int i = 0; i < 100; i++)
		{
			Cat cat = new Cat();
           	cat.ID = i;
			animalList.Add(cat);
		}
	}

 

Ακριβώς αυτό είναι που θα κάνω.

 

Επίσης πρέπει να βεβαιωθώ πως στην λίστα στέλνω μια κόπια και όχι το ίδιο το αντικείμενο, καθώς θέλω να κρατήσω μόνο την λίστα.

defacer: Σ' αυτή την περίπτωση βάζεις μέσα ένα αντίγραφο της μεταβλητής..

 

Επίσης πρέπει να βρω τρόπο να αποφύγω τα memory leaks.

Δημοσ.

Κανεις λαθος. Η C# δεν ειναι C++, ο gc δεν δουλευει σαν stack plus. O gc θα διαγραψει το αντικειμενο μονον οταν τελειωσει το lifetime του, και οταν εσυ το βαζεις (δεν γινεται copia) στην λιστα απλα του μεγαλωνεις το lifetime. Τελος εσυ πρεπει να ψαχνεις για τροπουε με τους οποιος θα αποφυγεις την αντιγραφη του αντικειμενου και οχι το αντιθετο.

 

 

Κατι κοντα σε αυτο της c# θα μπορουσες να το κανεις με Smart pointers ενα παραδειγμα πανω στο δικο σου

>#include <iostream>
#include <memory>
#include <vector>

class Animal
{
public:
       virtual void makeSound();
	virtual ~Animal(){}
};

void Animal::makeSound()
{
       std::cout << "makes a sound" << std::endl;
}

class Cat : public Animal
{
public:
       virtual void makeSound();
	virtual ~Cat()
	{
		std::cout << "Cat killed" << std::endl;
	}
};

void Cat::makeSound()
{
       std::cout << "cat ";
       this->Animal::makeSound();
}

class Bird : public Animal
{
public:
       virtual void makeSound();
	virtual ~Bird()
	{
		std::cout << "Bird killed" << std::endl;
	}
};

void Bird::makeSound()
{
       std::cout << "bird ";
       this->Animal::makeSound();
}
void CreateList(std::vector< std::shared_ptr<Animal> >& animalList)
{
Cat* cat = new Cat;
   Bird* bird = new Bird;
animalList.push_back(std::shared_ptr<Animal>(cat));
animalList.push_back(std::shared_ptr<Animal>(bird));
}

int main (int argc, const char * argv[])
{
{ // cat life time
	std::shared_ptr<Animal> catRef;
	{// list life time
		std::vector< std::shared_ptr<Animal> > animalList;
       
		CreateList(animalList);
       
		for (auto animalIter = animalList.begin(); animalIter < animalList.end(); animalIter++)
		{
		(*animalIter)->makeSound(); // ΟΚ
		}
		catRef = animalList[0]; // <-- kratame to cat
	} // <--- end of list lifetime kai mazi me ayth to bird alla oxi to cat
}// <-- edw psofaei to Cat

   return 0;}

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...