2014-10-14 6 views
5

ich etwas bin mit wie:C++ Typ basiertes Caching ohne Verwendung von statischen Speicher

struct VectorCache 
{ 
    template<typename T> 
    std::vector<T>& GetTs() 
    { 
     static std::vector<T> ts; 
     return ts; 
    } 
}; 

erstellen/einige Vektoren auf der enthaltenen Typ basiert zugreifen. Das funktioniert gut, solange ich nur ein Objekt vom Typ VectorCache habe, aber wenn ich mehrere Objekte verwende, bekomme ich dieselben Vektoren von allen Instanzen von VectorCache, da die Vektoren statische Variablen sind.

Ich habe versucht, die Vektoren als Elementvariablen mit etwas ähnlich wie boost::any zu verschieben und sie mit std::type_index von T zugreifen, aber das ist irgendwie langsamer als der direkte Zugriff, den ich zuvor verwendet habe.

Eine andere Möglichkeit ist, struct VectorCache in etwas wie template<int index> struct VectorCache umzuwandeln, aber das Problem ist immer noch da - ich muss vorsichtig sein, nur eine Instanz/Index zu haben, um korrektes Verhalten zu haben.

Ist es möglich, basierend auf T direkt auf die Vektoren zuzugreifen, und basiert die Caching-Instanz statt auf der Klasse?

+0

Und ich denke, Sie wollen nicht 'VectorCache ' (d. H. Move 'Vorlage ' von der Funktion in die Klasse), oder? Denn dann ist die Elementvariable einfach. – leemes

+0

Boost.Any ist im Grunde die Idee hinter jeder Lösung. Wenn das zu langsam ist, frage ich mich, ob eine andere Lösung ausreichend schnell sein wird. Eine Karte mit dem Schlüssel 'std :: type_index' kommt mir in den Sinn. –

+2

Wird 'VectorCache' in mehreren Dateien angezeigt? Wenn nicht, ist eine Konvention zum Instanziieren von "Template struct VectorCache" mit "__LINE__" ein üblicher, effektiver, schmutziger kleiner Hack, der mit einem Makro gelockert werden kann. –

Antwort

5

Sie könnten ein nicht geprüftes Analogon von Boost.Any versuchen. Sehen, ob das schnell genug für Sie ist (obwohl ich nicht glaube, es würde einen großen Unterschied machen):

#include <memory> 
#include <type_traits> 
#include <typeindex> 
#include <unordered_map> 
#include <vector> 

class AnyCache 
{ 
    struct TEBase 
    { 
     virtual ~TEBase() {} 
     virtual void * get() = 0; 
    }; 

    template <typename T> struct TEObject : TEBase 
    { 
     T obj; 
     virtual void * get() override { return static_cast<void *>(&obj); } 
    }; 

    std::unordered_map<std::type_index, std::unique_ptr<TEBase>> cache; 

public: 
    AnyCache(AnyCache const &) = delete; 
    AnyCache & Operator=(AnyCache const &) = delete; 

    template <typename T> decltype(auto) get() 
    { 
     using U = std::decay_t<T>; 
     using C = std::vector<U>; 

     std::unique_ptr<TEBase> & p = cache[typeid(U)]; 
     if (!p) { p = std::make_unique<TEObject<C>>(); } 
     return *static_cast<C *>(p->get()); 
    } 
}; 

Verbrauch:

AnyCache ac; 
ac.get<int>().push_back(20); 
ac.get<std::string>().push_back("Hello"); 
for (auto const & x : ac.get<Foo>()) { std::cout << x << '\n'; } 
+0

Danke für die Antwort - der Teil, den ich als "langsam" dachte, war nicht die Implementierung von boost :: any (ich benutzte etwas ähnliches, nicht boost :: any), es war die Suche in der map/unordered_map – Felics

2

Wenn - und es ist ein großes, wenn - Ihre VectorCache -verwenden Code ist nicht eingefädelt, können Sie dies tun:

struct VectorCache 
{ 
    VectorCache() : instance_counter_(++s_instance_counter_) { } 

    template<typename T> 
    std::vector<T>& GetTs() 
    { 
     static std::vector<std::vector<T>> tss; 
     if (tss.size() <= instance_counter_) 
      tss.resize(instance_counter_); 
     return tss[instance_counter_]; 
    } 

    size_t instance_counter_; 
    static size_t s_instance_counter_; 
}; 

// and define size_t VectorCache::s_instance_counter_; 

implementation on ideone.com

Mit al ittele Synchronisation können Sie es thread sicher machen, oder sogar Thread spezifisch, wenn das passt. Fügen Sie die Löschung der Kopierkonstruktion/-zuweisung usw. hinzu, wenn dies für Ihre beabsichtigte Verwendung sinnvoll ist.

+0

Und bete dass niemand Referenzen auf diese Vektoren speichert? –

+2

@KerrekSB: viele Daten haben Iterator- oder Zeiger-Ungültigkeitsmerkmale - Sie müssen sie verstehen und sehen, ob sie für Ihren beabsichtigten Client-Code geeignet sind, nicht beten ;-P. Sicher, es gibt zusätzliche Dinge, die Sie tun können, wenn nötig, aber ich werde diese Antwort nicht willkürlich auf dieses spezifische vermeintliche Bedürfnis erweitern, besonders wenn die erfolgreiche Verwendung des in der Frage veröffentlichten Codes andeutet, dass dies kein tatsächliches Problem ist. –

Verwandte Themen