C++ STL - Vektor pointerů na vektor pointerů na objekt?

Dobrý večer, řeším následující problém při návrhu programu v C++, který může využívat pouze věci z ANSI definice, tedy kontejnery z knihovny STL, žádný boost nebo něco podobného.

V jedné třídě (třebas A) potřebuji definovat pole (vektor) vektorů nestejné délky objektů jiné třídy (řekněme B). V konstruktoru chci toto pole naplnit prázdnými vektory (v té době vím, kolik jich bude, ale nevím, jakou budou mít jednotlivé vektory délku) a první vektor naplnit instancí třídy Z. Jsem trochu zmatený tím, jestli vše musí být definováno přes pointery nebo jestli je to možné udělat i pomocí automatických proměnných. Pole pointerů na vektory pointerů na objekty třídy B zní dost hrozivě , ale nevím, jak to udělat jinak, tak abych mohl za běhu programu dynamicky vytvářet objekty třídy B a ukládat je do vektorů. Dá se to udělat tak, aby se člověk mohl vyhnout alespoň používání pointeru na vektor nebo ne? Máte někdo nějaký nápad?


Sten

Re:C++ STL - Vektor pointerů na vektor pointerů na objekt?
« Odpověď #1 kdy: 02. 01. 2013, 19:59:12 »
std::vector<std::vector<Data>> je standardní řešení, žádné ukazatele nejsou potřeba. Pokud je to C++11, pak std::vector má i přesouvací konstruktor a výkonově to je potom ekvivalentní těm ukazatelům.

Re:C++ STL - Vektor pointerů na vektor pointerů na objekt?
« Odpověď #2 kdy: 02. 01. 2013, 20:14:27 »
C++11 to není. Jak ale mám to pole inicializovat a pak ho rozšiřovat? Když např. v některé funkci vytvořím objekt typu "Data" a přidám ho do vectoru, tak po vyskočení z funkce ten objekt zanikne, pokud není vytvořen pomocí pointeru a new - nebo ne? Nerozumím přesně tomu, jak ten std::vector funguje.

jarin

Re:C++ STL - Vektor pointerů na vektor pointerů na objekt?
« Odpověď #3 kdy: 02. 01. 2013, 20:48:35 »
vector má svůj alokátor. vector<Data> alokuje pro každou položku paměť o velikosti sizeof(Data). Pokud přidáš objekt do vectoru, tak se nakopíruje do paměti alokované vectorem.
V případě vector<Data *> to funguje úplně stejně, ale alokuje se sizeof(Data *) a kopíruje se hodnota ukazatele.

Sten

Re:C++ STL - Vektor pointerů na vektor pointerů na objekt?
« Odpověď #4 kdy: 02. 01. 2013, 21:56:26 »
O inicializaci a správu paměti se stará std::vector sám (přesněji to dělá jeho alokátor, který můžete nahradit za vlastní, ale ten výchozí v naprosté většině případů stačí). Pro rozšiřování má metodu insert(int, const Data&) a dvě „zkratky“ push_front(const Data&) a push_back(const Data&) (v C++11 mají všechny tyhle metody ještě přetíženou verzi pro přesouvání).

insert předaná data zkopíruje dovnitř std::vectoru pomocí kopírovacího konstruktoru, takže původní instance sice zanikne, ale její kopie tam bude. C++11 řeší výkon pomocí těch přesouvacích verzí, které volají přesouvací konstruktory, když ten objekt má stejně zaniknout. V C++ před-11 tohle není, takže se to u paměťově náročných tříd řeší tak, že se pomocí insert vloží prázdný objekt a až s tím se pracuje; u paměťově jednoduchých objektů se na to kašle v obou verzích :)

insert vrátí iterátor na vložený objekt (push_front ani push_back to nedělají, ale vložené objekty lze získat pomocí metod front() a back()), takže lze udělat něco podobného:
Kód: [Vybrat]
Data &data = *vector.insert(vector.size(), Data());
data.allocateALotOfMemory();

Případně můžete využít metodu resize(int, const Data& = Data()), která „roztáhne“ (nebo „scvrkne“) ten vektor a nové prvky vytvoří kopírováním předaného prvku:
Kód: [Vybrat]
vector.resize(vector.size() + 1);
Data &data = vector.back();
data.allocateALotOfMemory();

Pokud chcete postupně naplnit vektor o délce n, je nejlepší jej předalokovat najednou a až potom plnit, vyhnete se různých výkonostních problémů s kopírováním:
Kód: [Vybrat]
vector.resize(n);
for (std::vector<Data>::iterator it = vector.begin(), end = vector.end(); it != end; ++it) {
    it->allocateALotOfMemory();
}

Pozn. tohle všechno se týká C++ před-11; v C++11 by to bylo trochu jednodušší :)


Sten

Re:C++ STL - Vektor pointerů na vektor pointerů na objekt?
« Odpověď #5 kdy: 02. 01. 2013, 22:00:55 »
Hmm, insert používá iterátor místo pozice (insert(iterator, const Data&)), fix první ukázky:
Kód: [Vybrat]
Data &data = *vector.insert(vector.end(), Data());
data.allocateALotOfMemory();