Vektori pointtereista on ihan vitun masentava tapaus jos ne on dynaamisesti allokoitu yksi kerrallaan, se indirektio nimittäin syö ihan vitusti performanssia ja on monesti myös turhaa. Algoritmikurssilla yleensä unohdetaan kertoa että oikealla tietokoneella hommat ei toimi niinkuin koulussa opetetaan, ja datan perättäisyys on ihan hemmetin kova juttu kun prosessori osaa prefetchata seuraavat asiat cacheen jo ennen kuin luet niitä.
Eri kutsukerran perusteella eri alkion valinta onnistuu kyllä ilman performanssihintaa, mutta koodista saattaa tulla hieman rumaa riippuen lähestymistavasta. Erityisesti kun sanoit että joka funktiosta pitäisi tehdä kaksi versiota, alkaa hälytyskellot soida että olet ehkä tekemässä nyt jotain pahasti väärin. No, eipä mitään, vastataan nyt kysymykseesi joka tapauksessa, tässä olisi tyypin pohjalta templatoitu accessori, joka sallii myös kirjoittamisen sen läpi.
Koodi:
#include <string>
#include <vector>
#include <iostream>
struct Tietorakenne {
int luku;
std::string sana;
template<typename T> const T& value() const;
template<typename T> T& value();
};
template<> const int& Tietorakenne::value() const { return luku; }
template<> const std::string& Tietorakenne::value() const { return sana; }
template<> int& Tietorakenne::value() { return luku; }
template<> std::string& Tietorakenne::value() { return sana; }
template<typename T>
bool funktio(const std::vector<Tietorakenne*>& data1, const std::vector<Tietorakenne*>& data2, int i) {
return data1.at(i)->value<T>() > data2.at(i)->value<T>();
}
int main() {
std::vector<Tietorakenne*> a, b;
// jumalauta tämä vuotaa kumminkin muistia, mutta ihan sama nyt
a.push_back(new Tietorakenne{1, "banaani"});
b.push_back(new Tietorakenne{2, "apina"});
std::cout << "funktio<int>(a, b, 0) = " << (funktio<int>(a, b, 0) ? "True" : "False") << std::endl;
std::cout << "funktio<string>(a, b, 0) = " << (funktio<std::string>(a, b, 0) ? "True" : "False") << std::endl;
}
Muuta huomioitavaa:
Käytät vektorien indeksoimiseen .at(i) joka ei ole sama asia a[ i] (perkeleen foorumi ja bbcode nyt vittu), edellinen näistä tekee bounds checkin eli sulla on yhteensä neljä ylimääräistä branchia siinä funktiossa sen itse vertailun lisäksi. Tällä on usein huomattava hinta, vaikka prosessori nopeasti oppiikin olettamaan että se bounds check ei ikinä mene yli ja pistää pipelinen sen mukaan. Jos on tarkoitus tehdä nopeaa koodia niin se bounds check tehtäisiin jossain muualla kuin joka alkion kanssa erikseen.
Annoit alunperin pelkkänä referenssinä vektorit, const referenssit on parempi. Const correctness on hyvä opetella aikaisin, sitä kun on todella ankeaa käydä lisäämään mihinkään koodikantaan jälkeenpäin kun siinä tulee kunnon domino-efekti.
Heivaa se using namespace std helvettiin. Tulet kirjoittamaan myöhemmin paljon koodia headereihin jossa olisi tarkoitus määritellä tietorakenteita, ja sitten joudut viljelemään joka luokan sisään sen using namespace std erikseen. Sitähän ei todellakaan headerissa tule sanoa suoraan niin että se std-nimiavaruus vuotaa koko ohjelman globaaliscopeen.
Käytännössä std::vector<Tietorakenne>, elikkäs ilman pointteria, on usein paljon nopeampi kuin pointterin kanssa, kun tietorakenteet ovat pieniä ja yksinkertaisia. Lisäksi jos tuo vektori on ainoa paikka jossa pidetään kirjaa niistä pointtereista, joudut käsin deletoimaan ne alkiot aina samalla kun poistat sieltä vektorista jotain. Tämä tekee monista hienoista jutuista mahdottomia ja rumentaa koodia ihan vitusti. Jos se vektori on niiden tietorakenteiden omistaja ja jostain syystä sen on pakko olla pointteri, voit harkita std::vector<std::unique_ptr<Tietorakenne>> joka hoitaa automaattisen deallokaation puolestasi heti kun vektorista poistetaan pointteri, ja jos kääntäjän optimoinnit on päällä niin unique_ptr:llä ei ole myöskään yksinkertaisessa käytössä mitään performanssihintaa.
Joskus on kätevämpää olla tekemättä tietorakenteista omia structeja ja sanoa vain std:: pair<int, std::string> tai nykyään c++11 kanssa std::tuple<int, std::string> ... varsinkin jos ei tarvitse mitään operaattoreita määritellä sille tietorakenteelle eikä muitakaan jäsenfunktiota.