2009-05-18 9 views
13

Ich brauche ein shared_ptr ähnliches Objekt, das aber automatisch ein reales Objekt erzeugt, wenn ich versuche, auf seine Mitglieder zuzugreifen.Gibt es C++ faulen Zeiger?

Zum Beispiel habe ich:

class Box 
{ 
public: 
    unsigned int width; 
    unsigned int height; 
    Box(): width(50), height(100){} 
}; 

std::vector< lazy<Box> > boxes; 
boxes.resize(100); 

// at this point boxes contain no any real Box object. 
// But when I try to access box number 50, for example, 
// it will be created. 

std::cout << boxes[49].width; 

// now vector contains one real box and 99 lazy boxes. 

Gibt es eine Implementierung oder sollte ich meine eigene schreiben?

Antwort

17

Es ist sehr wenig Mühe, Ihre eigenen zu rollen.

template<typename T> 
class lazy { 
public: 
    lazy() : child(0) {} 
    ~lazy() { delete child; } 
    T &operator*() { 
     if (!child) child = new T; 
     return *child; 
    } 
    // might dereference NULL pointer if unset... 
    // but if this is const, what else can be done? 
    const T &operator*() const { return *child; } 
    T *operator->() { return &**this; } 
    const T *operator->() const { return &**this; } 
private: 
    T *child; 
}; 

// ... 

cout << boxes[49]->width; 
+2

wird es sinnvoll sein, Kind als auto_ptr –

+0

zu enthalten Aber wie würden Sie Boxen [49] -> Breite initialisieren, um einen nicht-trivialen initialisierten Wert (d. H. Nicht 0) zu haben? Sie möchten wahrscheinlich eine Schnittstelle haben, die den Konstruktor für * (Kästchen [49]) seinen Index als Argument erhält, damit er sich von den anderen Kästchen unterscheiden kann. Das bedeutet, dass Sie etwas anderes als std: vector verwenden und Sie in die Domäne spärlicher Vektoren/Matrizen versetzen. –

+2

Sie können boost :: optional anstelle des Kindzeigers verwenden. Die Verwendung von boost :: optional bedeutet, dass Sie von seiner Stack-Zuweisung profitieren. Kein Heap wird verwendet, dann –

2

Ich habe noch nie von so etwas gehört, aber dann wieder gibt es viele Dinge, von denen ich noch nie gehört habe. Wie würde der "faule Pointer" nützliche Daten in die Instanzen der zugrunde liegenden Klasse schreiben?

Sind Sie sicher, dass ein sparse matrix nicht das ist, was Sie wirklich suchen?

+1

Warum haben Sie auf die spärliche Matrix hingewiesen? –

+0

Weil eine dünn besetzte Matrix einen ähnlichen (wenn auch nicht identischen) Bedarf erfüllt. Beachten Sie, dass das Beispiel des Posters einen Vektor von "faulen Zeigern" zeigt; das klingt sehr nach einer spärlichen Matrix. –

0

Soweit ich weiß, gibt es keine bestehende Implementierung dieser Art von Sache. Es wäre nicht schwer, eins zu erstellen.

10

boost::optional verwenden, können Sie so etwas haben:

// 100 lazy BigStuffs 
std::vector< boost::optional<BigStuff> > v(100); 
v[49] = some_big_stuff; 

100 faul des Konstrukts und eine echte some_big_stuff zu v[49] zuweisen. boost::optional wird keinen Heap-Speicher verwenden, aber placement-new verwenden, um Objekte in einem Stapelspeicherpuffer zu erstellen. Ich würde einen Wrapper um boost::optional wie folgt erstellen:

template<typename T> 
struct LazyPtr { 
    T& operator*() { if(!opt) opt = T(); return *opt; } 
    T const& operator*() const { return *opt; } 

    T* operator->() { if(!opt) opt = T(); return &*opt; } 
    T const* operator->() const { return &*opt; }  
private: 
    boost::optional<T> opt; 
}; 

Die jetzt boost::optional dafür stopft verwendet. Es sollte an Ort und Stelle Konstruktion wie dieses (Beispiel auf op*) unterstützen:

T& operator*() { if(!opt) opt = boost::in_place(); return *opt; } 

Welche nicht erfordern würde jedes Kopie-ing. Das aktuelle boost-Handbuch enthält jedoch nicht die Überlast des Zuweisungsoperators. Die Quelle tut dies jedoch. Ich bin mir nicht sicher, ob das nur ein Defekt im Handbuch ist oder ob seine Dokumentation absichtlich weggelassen wird. Also würde ich den sichereren Weg mit einer Kopierzuweisung unter Verwendung T() verwenden.

+2

'vector > v (100)' wird 100 * sizeof (Box) verwenden, was vielleicht in Ordnung ist, aber vielleicht will OP keinen Speicher für Boxen verwenden, die nicht zugewiesen sind. Da OP mehr Anforderungen nicht beschrieben hat, wissen wir nicht ... – ephemient

+0

Sie haben Recht, das ist ein guter Punkt :) –

+0

Richtig, ich möchte nicht Platz auf nicht zugewiesene Objekte verschwenden. –