2017-01-06 4 views
0

geschrieben Einige man die Fragen zu diesem Muster, aber mit nicht der Lösung der in meinem Kopf gestellten Frage so mit den Abfragen Entsendung ich habe ...Verwirrung mit Beispiel Erklärung von Prototype Mustern in C++

In obigem Beispiel, wenn Alle Instanzen werden durch die Variable s_prototypes initialisiert und das nächste Mal, wenn irgendein Objekt davon durch das neue Objekt in der Klonmethode ersetzt wird, was wird dann mit dem existierenden Objekt geschehen? Wird es Speicherlecks erzeugen?

Soweit ich von oben Beispiel zwei Aussage verstehen verwechselst mich

class Stooge { 
public: 
    virtual Stooge* clone() = 0; 
    virtual void slap_stick() = 0; 
}; 

class Factory { 
public: 
    static Stooge* make_stooge(int choice); 
private: 
    static Stooge* s_prototypes[4]; 
}; 

int main() { 
    vector roles; 
    int    choice; 

    while (true) { 
     cout << "Larry(1) Moe(2) Curly(3) Go(0): "; 
     cin >> choice; 
     if (choice == 0) 
     break; 
     roles.push_back(
     Factory::make_stooge(choice)); 
    } 

    for (int i=0; i < roles.size(); ++i) 
     roles[i]->slap_stick(); 
    for (int i=0; i < roles.size(); ++i) 
     delete roles[i]; 
} 

class Larry : public Stooge { 
public: 
    Stooge* clone() { return new Larry; } 
    void slap_stick() { 
     cout << "Larry: poke eyes\n"; } 
}; 
class Moe : public Stooge { 
public: 
    Stooge* clone() { return new Moe; } 
    void slap_stick() { 
     cout << "Moe: slap head\n"; } 
}; 
class Curly : public Stooge { 
public: 
    Stooge* clone() { return new Curly; } 
    void slap_stick() { 
     cout << "Curly: suffer abuse\n"; } 
}; 

Stooge* Factory::s_prototypes[] = { 
    0, new Larry, new Moe, new Curly 
}; 
Stooge* Factory::make_stooge(int choice) { 
    return s_prototypes[choice]->clone(); 
} 

Output 
Larry(1) Moe(2) Curly(3) Go(0): 2 
Larry(1) Moe(2) Curly(3) Go(0): 1 
Larry(1) Moe(2) Curly(3) Go(0): 3 
Larry(1) Moe(2) Curly(3) Go(0): 0 
Moe: slap head 
Larry: poke eyes 
Curly: suffer abuse 

Aber wenn wir Klon-Methode make_stooge Methode aufrufen, wird es neue Objekt zurück, Wenn das neue Objekt zurückgibt und ersetzt sie durch bestehende dann das vorhandene Objekt hier Speicherleck schaffen wird (weil neue Betreiber vollständig separates Objekt erstellt und nicht wieder eine hier vorhandene) ....

so dieses Ding ist mir bei diesem Beispiel verwirrend ....

+0

* Wenn das zurückgibt neues Objekt und ersetzt sie durch bestehende * - das ist nicht in Ihrem Code geschrieben geschieht. –

Antwort

1

Es ist n o Speicherleck in Ihrem Code, weil die neu angelegten Objekte sorgfältig in einem vector (hier roles) gespeichert werden.

Sie werden dann von diesem Vektor verwendet, und zerstört, bevor das Programm endet:

... 
    for (int i=0; i < roles.size(); ++i) 
     delete roles[i]; 
} 

Aber ein return 0; vor Haupt Verlassen schöner wäre ...

Und es ist gute Praxis, eine zu schaffen virtueller Destruktor für Klassen, die abgeleitet werden sollen: Wenn Larry usw. einen nicht trivialen Destruktor hat, wird er nicht verwendet, wenn Sie ihn über einen Basisklassenzeiger löschen:

class Stooge { 
public: 
    virtual Stooge* clone() = 0; 
    virtual void slap_stick() = 0; 
    virtual ~Stooge() {} 
}; 

Für die 4 statischen Objekte s_prototypes werden sie beim Start des Programms statisch initialisiert, bevor main aufgerufen wird, und sie werden nie geändert. Ihre clone Methode wird aufgerufen, um neue Objekte zu erstellen, aber s_prototype wird immer noch auf das alte Objekt zeigen - der Grund, warum es wichtig ist, dass die neu erstellten Objekte gespeichert und gelöscht werden.

Es gibt tatsächlich ein Speicherleck für diese 4 Objekte, da sie niemals explizit zerstört werden. Es wird oft als akzeptabel angesehen, auf diese Weise statische Objekte zu verlassen, da ihre Lebensdauer bis zum Programmende reicht, wenn der gesamte Speicher freigegeben ist. Wenn es wichtig war für den destructor genannt werden, sollten Sie auch statische Instanzen für sie erstellen:

static Larry _larry; 
static Moe _moe; 
static Curly _curly; 
Stooge* Factory::s_prototypes[] = { 
    0, &_larry, &_moe, &_curly 
}; 

Wenn Sie die Zerstörung explizit mit machen:

virtual ~Stooge() { 
     cout << "Delete " << this << endl; 
    } 

und leicht das Ende des Programms ändern :

for (int i=0; i < roles.size(); ++i) 
     delete roles[i]; 
    cout << "END" << endl; 
    return 0; 
} 

wird die Ausgabe wie:

... 
Delete 001ADB78 
END 
Delete 00F350A0 
Delete 00F3509C 
Delete 00F35098 

deutlich zeigt, dass die statischen Objekte nach dem Ende des Programms zerstört werden.

+0

Die Frage betrifft die Zeiger in 's_prototypes', die niemals gelöscht werden. –

+0

ja Sie sind richtig verstanden @DavidScarlett .... Aber was ist die Lösung für diese Frage ... –

+0

können wir diesen Zeiger in Klon-Methode verwenden, um das vorhandene Objekt stattdessen zurückzugeben? in Prototyp-Muster –

1

Nun, Sie haben Recht, dass die Zeiger in s_prototypes nie gelöscht werden, aber mindestens diese Objekte sollen sowieso für die gesamte Laufzeit des Programms dauern, es sei denn, es gab eine bestimmte Aktion, die in ihrem ausgeführt werden musste Destruktoren, dann ist es nicht das Ende der Welt, wenn sie nicht vor Programmende gelöscht werden. Dies ist bei weitem nicht so schlimm wie Code, der ständig Speicher verlieren könnte, was dazu führen würde, dass der vom Programm verwendete Speicher weiter zunimmt.

Wenn Sie wollten, könnten Sie sie mit statischen Instanzen ersetzen stattdessen wie folgt aus:

#include <iostream> 
#include <vector> 
using namespace std; 

class Stooge { 
public: 
    virtual Stooge* clone() = 0; 
    virtual void slap_stick() = 0; 
    virtual ~Stooge() = default; 
}; 

class Larry : public Stooge { 
public: 
    Stooge* clone() { return new Larry; } 
    void slap_stick() { 
     cout << "Larry: poke eyes\n"; } 
}; 
class Moe : public Stooge { 
public: 
    Stooge* clone() { return new Moe; } 
    void slap_stick() { 
     cout << "Moe: slap head\n"; } 
}; 
class Curly : public Stooge { 
public: 
    Stooge* clone() { return new Curly; } 
    void slap_stick() { 
     cout << "Curly: suffer abuse\n"; } 
}; 

class Factory { 
public: 
    static Stooge* make_stooge(int choice); 
private: 
    static Larry larry; 
    static Curly curly; 
    static Moe moe; 
}; 

int main() { 
    vector<Stooge*> roles; 
    int    choice; 

    while (true) { 
     cout << "Larry(1) Moe(2) Curly(3) Go(0): "; 
     cin >> choice; 
     if (choice == 0) 
     break; 
     roles.push_back(
     Factory::make_stooge(choice)); 
    } 

    for (int i=0; i < roles.size(); ++i) 
     roles[i]->slap_stick(); 
    for (int i=0; i < roles.size(); ++i) 
     delete roles[i]; 
} 

Stooge* Factory::make_stooge(int choice) { 
    switch(choice) { 
    case 1: 
     return larry.clone(); 
    case 2: 
     return curly.clone(); 
    case 3: 
     return moe.clone(); 
    default: 
     return nullptr; 
    } 
}