2015-06-27 5 views
8

Ich versuche herauszufinden, wie ich durch einen Container (wie Std :: Vector) von Objekten, die eine gemeinsame Basisparentklasse zusammenhängende im Speicher gemeinsam verwenden.Iterieren durch Objekte mit einer gemeinsamen Basisklasse in unterschiedlichen Speicher

Um das Problem zu demonstrieren, verwenden wir die folgenden Beispiele.

class Base 
{ 
public: 
    Base(); 
    virtual void doStuff() = 0; 
}; 

class DerivedA : public Base 
{ 
private: 
    //specific A member variables 
public: 
    DerivedA(); 
    virtual void doStuff(); 
}; 

class DerivedB : public Base 
{ 
private: 
    //specific B member variables 
public: 
    DerivedB(); 
    virtual void doStuff(); 
}; 

nun mit std :: vector die Objekte in zusammenhängenden Speicher zu wiederholen halten würde, aber wir würden dort erleben Aufschneiden nicht Raum für die abgeleiteten Eigenschaften ist.

So haben wir wie polymorphe Technik Zeiger zu verwenden, so

int main() 
{ 
    std::vector<Base*> container; 
    container.push_back(new DerivedA()); 
    container.push_back(new DerivedB()); 

    for (std::vector<Base*>::iterator i = container.begin(); i!=container.end(); i++) 
    { 
     (*(*i)).doStuff(); 
    } 
} 

Soweit ich weiß, dass sollte in Ordnung, dass die Klassen implementiert sind gegeben arbeiten.

Problem: Nun wird der Vektor Zeiger in zusammenhängenden Speicher enthält, aber das bedeutet nicht, dass die Adressen, die sie verweisen auf sind.

Wenn ich also jederzeit Objekte in den Vektor löschen und einfügen kann, werden die Objekte überall im Speicher verteilt.

Frage: Es scheint wie jeder schlägt die std :: vector Art und Weise zu tun, aber warum es nicht als problematisch angesehen, dass sie nicht zusammenhängend im Speicher Iterable (vorausgesetzt, wir tatsächlich den Zeiger)?

Bin ich gezwungen, die Copy-Pasta-Art zu machen?

int main() 
{ 

    std::vector<DerivedA> containerA; 
    DerivedA a; 
    containerA.push_back(a); 

    std::vector<DerivedB> containerB; 
    DerivedB b; 
    containerB.push_back(b); 

    for (std::vector<DerivedA>::iterator i = containerA.begin(); i!=container.end(); i++) 
    { 
     (*i).doStuff(); 
    } 
    for (std::vector<DerivedB>::iterator i = containerB.begin(); i!=container.end(); i++) 
    { 
     (*i).doStuff(); 
    } 
} 

ich es erraten könnte keine wirkliche Lösung für dieses Problem sein, da Objekte in verschiedenen Größen linear im Speicher zu halten, dass es nicht sinnvoll, aber wenn jemand mir einen Rat geben kann, würde ich es zu schätzen wissen.

+0

Ich denke, dein letzter Satz fasst es zusammen. Wenn Sie die Copy-Paste nicht aushalten können, verwenden Sie vielleicht einen Container, um Ihre Vektoren zu verwalten. Ich hatte bereits einen [hier] (http://codereview.stackexchange.com/questions/87729/storing-collections-of-objects-of-any-type), wenn Sie ein paar Ideen haben wollen. – Quentin

+0

Offhand Ich kann mir eine Möglichkeit vorstellen, geerbte Typen zusammenhängend im Speicher zu behalten. Aber Sie würden zufälligen Zugriff verlieren und wahrscheinlich andere Einschränkungen haben. In der Tat wäre es so, als würde man gleichzeitig die schlechtesten Aspekte von Vektor und Liste bekommen. Wie bei allem in der Softwareentwicklung gibt es irgendwo einen Kompromiss. – TheUndeadFish

+3

Wie viel variieren ihre Größen? Geht es Ihnen gut, wenn Sie die Größe abgeleiteter Größe und einen ungefähren Overhead-Zeiger verwenden? Sind Sie daran gebunden, Vererbung zu verwenden, um Polymorphie zu implementieren? Wie groß ist die Schnittstelle? Hast du Verstärkung? Wird die Menge abgeleiteter Klassen (zur Kompilierzeit) festgelegt und begrenzt? Dies sind keine müßigen Fragen, Antworten auf sie können einige Lösungen durchführbar machen und andere nicht. – Yakk

Antwort

-3

std::vector<T> Iteratoren davon ausgehen, dass die Objekte in dem zusammenhängenden Speicher des Typs sind T, std::vector<T>::iterator::operator++sizeof T invariant hält - das heißt, sie nicht die spezifische Instanz für Größendaten zu konsultieren.

Im Wesentlichen kann man sich vorstellen vector und vector::iterator als dünne Fassade über einen T* m_data Zeiger, so dass iterator++ ist wirklich nur ein grundlegender Zeiger Betrieb.

Wahrscheinlich müssen Sie eine benutzerdefinierte allocator verwenden und an Ort und Stelle new Ihre Daten vorzubereiten, entweder durch Indizierung begleitet, Verknüpfung usw. Vielleicht so etwas wie http://www.boost.org/doc/libs/1_58_0/doc/html/intrusive/slist.html

See boost::stable_vector auch

+0

Verknüpfte Listen sind nie zusammenhängend im Speicher, ich sehe nicht, wie dies die Frage beantwortet, noch, wie es effektiv anders ist als ein Vektor >. –

-3

std::vector Ordnet die betrachten Objekte im fortlaufenden Speicher, aber die Objektzeiger, die Sie im Vektor speichern, sind es nicht. So iterieren Sie durch vector. Der folgende Code ist in C++ 14 geschrieben. Das beschriebene Problem ist mit dieser Lösung nicht lösbar, da die Objektzeiger im fortlaufenden Speicher, nicht aber die eigentlichen Objekte gespeichert sind.

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

class Base 
{ 
public: 
    Base() {} 
    virtual void doStuff() = 0; 
}; 

class DerivedA : public Base 
{ 
private: 
    //specific A member variables 
public: 
    DerivedA() : Base() {} 
    virtual void doStuff() { 
     std::cout << "Derived Class A - Do Stuff" << std::endl; 
    } 
}; 

class DerivedB : public Base 
{ 
private: 
    //specific B member variables 
public: 
    DerivedB() : Base() {} 
    virtual void doStuff() { 
     std::cout << "Derived Class B - Do Stuff" << std::endl; 
    } 
}; 
int main() { 
    // your code goes here 
    std::vector<std::unique_ptr<Base> > container; 
    container.push_back(std::make_unique<DerivedA>()); 
    container.push_back(std::make_unique<DerivedB>()); 

    std::for_each(container.begin(), container.end(),[](std::unique_ptr<Base> & b) { 
     b->doStuff(); 
    }); 
    return 0; 
} 

Live Demo here.

+0

_ "' std :: vector' weist nicht alle Objekte im fortlaufenden Speicher zu "_ Ja, tut es. Und du bist der Frage nicht einmal nahe gekommen. Es war auch nicht "C++ 0x" seit vor vier Jahren. Es wurde C++ 11. Und auch das wurde inzwischen von C++ 14 abgelöst, das auch relativ alt ist ... –

+0

Ja, das stimmt. Ich habe diesen Code in C++ 14 selbst ausgeführt. und was ich sagen wollte, ist, dass die Objekte nicht im fortlaufenden Speicher angeordnet sind. Ich werde die Antwort aktualisieren –

+0

Ja, Vektorelemente sind immer im zusammenhängenden Speicher zugeordnet. In Ihrem Fall sind diese Elemente Zeiger und die Zeiger sind immer noch im zusammenhängenden Speicher zugeordnet. –

Verwandte Themen