2017-02-02 6 views
2

für pädagogische Zwecke, war ich bereits heute eine Wrapper-Klasse Implementierung unten definiert (dies wird aus einem Buch entnommen):Einfache Wrapper-Klasse vs. Smart-Pointer

#ifndef WRAPPER_H 
#define WRAPPER_H 

template<class T> 
class Wrapper 
{ 
public: 
    Wrapper() 
    { dataPtr = 0; } 

    Wrapper(const T& inner) 
    { 
    dataPtr = inner.clone(); 
    } 

    Wrapper(const Wrapper<T> &original) 
    { 
    if (original.dataPtr != 0) 
     dataPtr = original.dataPtr->clone(); 
    else 
     dataPtr = 0; 
    } 

    Wrapper &operator =(const Wrapper<T> &original) 
    { 
    if (this != &original) 
    { 
     if (dataPtr != 0) 
      delete dataPtr; 

     dataPtr = (original.dataPtr !=0) ? original.dataPtr->clone() : 0; 
    } 
    return *this; 
    } 

    ~Wrapper() 
    { 
    if (dataPtr != 0) 
     delete dataPtr; 
    } 

    T &operator*() 
    { 
    return *dataPtr; 
    } 

    const T&operator*() const 
    { 
    return *dataPtr; 
    } 

    T *operator->() 
    { 
    return dataPtr; 
    } 

    const T * const operator->() const 
    { 
    return dataPtr; 
    } 
private: 
    T *dataPtr; 
}; 

#endif 

Die Hauptidee ist als Zeiger zu handeln , mit dem zusätzlichen Vorteil der Speicherverwaltung, Kopierkonstruktor, Destruktor und Zuweisungsoperator. Es umschließt Klassen mit einer Klon-Methode: Sie geben einen Zeiger auf eine Kopie von sich selbst zurück (nicht zu sich selbst, zu einer neuen Kopie, die mit newClass(*this) erstellt wurde).

In gewisser Weise scheint es wie ein unique_ptr, weil das umschlossene Objekt nur über diesen Wrapper zugänglich ist. Es gibt einen Unterschied, um den es in meiner Frage geht. In dieser Wrapperklasse gibt es einen Konstruktor, der durch Akzeptieren eines Verweises auf ein Objekt der Klasse definiert wird, die umgebrochen wird (der erste Konstruktor im obigen Code).

Dies ist sehr praktisch. Nehmen wir an, wir haben die Klassen A und B, und der Konstruktor für B nimmt Bezug auf eine Wrapper<A>. Dann kann ich ein Objekt mit einem anderen Objekt B konstruieren A:

A object1; 
B object2(A); 

Dies liegt daran, object2 verwendet wird, ein Wrapper<A> (dann an den Konstruktor B) unter Verwendung des oben genannte Wrapper Konstruktor zu konstruieren.

Ist es möglich, dies mit einem der Smartpointer in std::memory zu tun? Mein Hauptziel ist hier Bildung, aber in der Praxis möchte ich das Rad nicht neu erfinden.

+1

Kopierkonstruktor ist nicht für eindeutige Zeiger verfügbar, da sie nach einer Kopie nicht mehr eindeutig sind. Geteilte Zeiger sind stattdessen _copyable_, wobei die Kopie einfach die Tatsache durchsetzt, dass sie _die Eigentümerschaft des spitzen Objekts _miteinander teilen. – skypjack

+0

Das sieht aus, als würde es tiefe Kopien machen, anstatt einen Zeiger zu teilen/zu bewegen. – user4581301

+0

Sieht aus wie ein intrusive_ptr –

Antwort

5

A Smart Pointer soll Eigentum Semantik, zur Verfügung zu stellen, die sein kann kategorisiert (und mit den verfügbaren C++ - Standardimplementierungen):

  • einzigartige Eigentümer immer übertragen wird, wenn sie um
  • geben
  • geteilt Es gibt keinen einzigen Besitzer, der Smart-Pointer-Referenzen zählt, und verstirbt, wenn diese fallen auf 0
  • schwach Ein abhängiger Zeiger, der jedoch die Möglichkeit bietet zu überprüfen, ob der referenzierte Zeiger noch gültig ist

Das ist ganz anders als Ihre Wrapper-Implementierung.

1

ja all das ist möglich .. und als referenz .. und weil ich mal auch sowas implementiert habe .. (auch für bildungszwecke) .. ich kann den code teilen, den ich für einen smartpointer gemacht habe, mit zählwerk. . das heißt, Sie können so viele Kopien davon erstellen, wie Sie wollen, dass, wenn die letzte Kopie zerstört wird das Objekt gelöscht wird

#ifndef UberPointer 
#define UberPointer UPointer 

template <class UClass> class UPointer 
{ 
private: 
    struct UPointerRef 
    { 
     UClass* pObject; 
     int _nCount; 
     UPointerRef(UClass* pRef){_nCount=0;pObject = pRef;} 
     ~UPointerRef(){if(pObject)delete pObject;} 
     void AddRef(void){++_nCount;} 
     void RemoveRef(void){if (--_nCount <= 0){delete this;}} 
    }; 
    UPointerRef* _pRef; 

public: 
    UPointer() 
    { 
     _pRef = new UPointerRef(0x0); 
     _pRef->AddRef(); 
    } 
    UPointer(UClass* pPointer) 
    { 
     _pRef = new UPointerRef(pPointer); 
     _pRef->AddRef(); 
    } 
    UPointer(UPointer<UClass> &oPointer) 
    { 
     _pRef = oPointer._pRef; 
     _pRef->AddRef(); 
    } 
    ~UPointer(void) 
    { 
     _pRef->RemoveRef(); 
    } 
    UClass* GetObject() 
    { 
     ASSERT(_pRef->pObject); 
     return _pRef->pObject; 
    } 
    operator UClass*(void) 
    { 
     ASSERT(_pRef->pObject); 
     return _pRef->pObject; 
    } 
    UClass& operator*(void) 
    { 
     ASSERT(_pRef->pObject); 
     return *(_pRef->pObject); 
    } 
    UClass* operator->(void) 
    { 
     ASSERT(_pRef->pObject); 
     return (_pRef->pObject); 
    } 
    UPointer& operator=(UPointer<UClass> &oPointer) 
    { 
     _pRef->RemoveRef(); 
     _pRef = oPointer._pRef; 
     _pRef->AddRef(); 
     return *this; 
    } 
    UPointer& operator=(UClass* pPointer) 
    { 
     _pRef->RemoveRef(); 
     _pRef = new UPointerRef(pPointer); 
     _pRef->AddRef(); 
     return *this; 
    } 
    bool operator==(UClass* pPointer) 
    { 
     return _pRef->pObject == pPointer; 
    } 
    bool operator!=(UClass* pPointer) 
    { 
     return _pRef->pObject != pPointer; 
    } 
    bool operator !(void) 
    { 
     return (_pRef->pObject == 0x0); 
    } 
    operator bool(void) 
    { 
     return (_pRef->pObject != 0x0); 
    } 
}; 
#endif 
+1

Es sieht nicht so aus, als würden Sie gegen die Regeln verstoßen, aber Sie werden das hier trotzdem weglassen: [Welche Regeln gelten für die Verwendung eines Unterstrichs in einer C++ - ID?] (Http://stackoverflow.com/questions/228783/what -are-the-rules-über-mit-einem-unterstreichen-in-ac-identifier) ​​ – user4581301

+0

yeah .. im laufe der jahre habe ich irgendwie angefangen, meine eigene art von notation zu entwickeln .. ist nicht C++ standart .. aber ist cross Sprache verwendbar .. so benutze ich immer die gleiche Notation, wenn ich zwischen den Sprachen im selben Projekt wechseln muss. (C#/javascript/SQL) .. es reduziert die Belastung der Anpassung jedes Mal, wenn Sie sich bewegen .. – CaldasGSM

+0

Namenskonventionen sind ein gutes Ding. Ich verwende viele Präfixe und Suffixe als Mnemonics und Hinweise. Die Sorge mit dem Unterstrich besteht darin, dass Sie versehentlich einen Namen verwenden könnten, der der Standardbibliotheksimplementierung gehört und Compilerfehler oder wirklich seltsame Laufzeitergebnisse liefert. – user4581301

1
A object1; 
B object2(A); 

Ist es möglich, dies mit einem des Smart-Pointer in std :: Speichern zu tun?

Mit Standard-Smart-Zeigern erhalten Sie keine Semantik für tiefe Kopien. Sie haben entweder eine flache Kopie Semantik (mit std :: shared_ptr) oder eine Bewegung Semantik (mit std :: unique_ptr). Nichts hindert Sie jedoch daran, in Ihrer Klasse eine clone()-Methode zu erstellen, die einen intelligenten Zeiger zurückgibt. Auf diese Weise können Sie Ihre tiefe Kopie haben, wenn Sie eine benötigen, während Sie immer noch von der Besitz-Semantik profitieren, die mit intelligenten Zeigern geliefert wird.

Verwandte Themen