2013-03-19 4 views
16

In C++ können Sie dies tun:Kompilierzeitpopulation von anderen Datenstrukturen als Arrays?

static const char * [4] = { 
    "One fish", 
    "Two fish", 
    "Red fish", 
    "Blue fish" 
}; 

... und das gibt Ihnen eine schöne Nur-Lese-Array-Daten-Struktur, die keine CPU-Zyklen dauert zur Laufzeit initialisieren, da alle Daten, wurde für Sie (in den schreibgeschützten Speicherseiten der ausführbaren Datei) vom Compiler ausgelegt.

Aber was wäre, wenn ich lieber eine andere Datenstruktur als ein Array verwenden würde? Zum Beispiel, wenn ich meine Datenstruktur haben schnelle Lookups über einen Schlüssel wollte, würde ich so etwas zu tun haben:

static std::map<int, const char *> map; 

int main(int, char **) 
{ 
    map.insert(555, "One fish"); 
    map.insert(666, "Two fish"); 
    map.insert(451, "Red fish"); 
    map.insert(626, "Blue fish"); 

    [... rest of program here...] 
} 

... die weniger elegant ist und weniger effizient als die Datenstruktur Karte ist während der Laufzeit zur Verfügung gestellt wurde, obwohl alle notwendigen Daten zur Kompilierungszeit bekannt waren und daher die Arbeit (theoretisch) hätte durchgeführt werden können.

Meine Frage ist, gibt es eine Möglichkeit in C++ (oder C++ 11) eine schreibgeschützte Datenstruktur (z. B. eine Karte) zu erstellen, deren Daten vollständig zur Kompilierungszeit eingerichtet und somit vorbelegt und bereit zur Laufzeit, so wie ein Array sein kann?

Antwort

4

nicht leicht, nein. Wenn Sie versuchen, Ihr erstes Beispiel mit malloc zu tun, würde es offensichtlich nicht zur Kompilierzeit arbeiten. Da jeder einzelne Standardcontainer new verwendet (gut, std::allocator<T>::allocate(), aber wir werden vorgeben, dass es new für jetzt ist), können wir dies nicht zur Kompilierzeit tun.

Das gesagt worden ist, hängt davon ab, wie viel Schmerz Sie bereit sind zu durchlaufen, und wie viel Sie zurück zur Kompilierzeit schieben möchten. Sie können dies sicherlich nicht mit Standardbibliotheken machen. Mit boost::mpl auf der anderen Seite ...

#include <iostream> 

#include "boost/mpl/map.hpp" 
#include "boost/mpl/for_each.hpp" 
#include "boost/mpl/string.hpp" 
#include "boost/mpl/front.hpp" 
#include "boost/mpl/has_key.hpp" 

using namespace boost::mpl; 

int main() 
{ 
    typedef string<'One ', 'fish'> strone; 
    typedef string<'Two ', 'fish'> strtwo; 
    typedef string<'Red ', 'fish'> strthree; 
    typedef string<'Blue', 'fish'> strfour; 

    typedef map<pair<int_<555>, strone>, 
     pair<int_<666>, strtwo>, 
     pair<int_<451>, strthree>, 
     pair<int_<626>, strfour>> m; 

    std::cout << c_str<second<front<m>::type>::type>::value << "\n"; 
    std::cout << has_key<m, int_<666>>::type::value << "\n"; 
    std::cout << has_key<m, int_<111>>::type::value << "\n"; 
} 
+0

Stört es dich, meine Frage ähnlich aber Vektor zu beantworten? Meine Werte sind vom Typ double http://stackoverflow.com/questions/15471122/getting-started-with-boost-mpl-with-vector-and-push-back – woosah

8

Wenn Sie eine Karte (oder einen Satz) möchten, können Sie stattdessen eine binary tree stored as an array verwenden. Sie können behaupten, dass es zur Laufzeit korrekt in Debug-Builds geordnet ist, aber in optimierten Builds können Sie einfach davon ausgehen, dass alles korrekt arrangiert ist und dann die gleichen binären Suchoperationen ausführen wie std :: mapping, aber mit dem Underlying Speicher ist ein Array. Schreiben Sie einfach ein kleines Programm, um die Daten für Sie zu speichern, bevor Sie es in Ihr Programm einfügen.

+2

Heaps sind nicht ausreichend für die binäre Suche bestellt. Sie benötigen einen tatsächlichen binären Suchbaum (oder ein entsprechendes moralisches Äquivalent). – rici

+0

Oh natürlich hast du recht. Ich werde meine Antwort aktualisieren (die ähnlich bleibt wie vorher, nur nicht mit Heaps). –

0

Ja, C++ 11 erlaubt initializers Brace:

std::map<int, const char *> map = { 
    { 555, "One fish" }, 
    { 666, "Two fish" }, 
    // etc 
}; 
+9

Ja, aber das wird die Datenstruktur zur Laufzeit aufbauen, was das OP vermeiden will. –

+1

@JohnZwinck ah mein Schlechter, ich verstand OP wollte nur eine Syntax mit statischer Initialisierung kompatibel. Er las seine Frage erneut, aber seine Anforderungen waren offensichtlich. Schande über mich. – syam

+0

Btw, könnten Sie Initialisierungsliste diese als const std :: map konstruieren? – Inverse

2

Es ist erwähnenswert, dass Ihr Problem rührt von der Tatsache Sie Karte verwenden. Karten werden oft überstrapaziert. Die alternative Lösung für eine Karte ist ein sortierter Vektor/Array. Karten werden nur dann "besser" als Karten, wenn sie zum Speichern von Daten unbekannter Länge oder (und nur manchmal) bei häufigen Datenänderungen verwendet werden.

Die Funktionen std :: sort, std :: lower_bound/std :: upper_bound sind was Sie brauchen. Wenn Sie die Daten selbst sortieren können, benötigen Sie nur eine Funktion, lower_bound, und die Daten können const sein.

+0

"Maps werden nur" besser "als Maps"? Meinst du "besser als Vektoren"? –

+0

Karte war nur ein Beispiel ... Sie könnten jede (Nicht-Array-) Datenstruktur ersetzen und die Frage wäre die gleiche. –

+0

@ Jeremy Friesner: Ja, ich weiß, es war ein Beispiel. Was ich meinte ist, dass "Karten besser werden als Karten", klingt wie ein Tippfehler. –