smartPointer



  • Ich habe mal versucht eine eigene kleine smartPointer Klasse zu bauen um besser vertehen zu können was da genau passiert.
    Erst mal meine Klasse:
    Header:

    #ifndef __SMARTPOINTER_H__
    #define __SMARTPOINTER_H__

    template< typename T > class smartPointer
    {
    private:
    	T* ptr;
    public:
    	smartPointer( );
    	smartPointer( T* value );
    	~smartPointer( );
    
    	T* operator->( ) const;
    	T operator*( ) const;
    };
    
    #endif __SMARTPOINTER_H__
    
    include "SmartPointer.h"
    
    template< typename T >
    smartPointer< T >::smartPointer( )
    {
    	ptr = NULL;
    	cout << "Called !" << endl;
    }
    
    template< typename T >
    smartPointer< T >::smartPointer( T *value )
    {
    	ptr = value;
    	cout << "Called !" << endl;
    }
    
    template< typename T >
    smartPointer< T >::~smartPointer( )
    {
    	cout << "DESTROYED !" << endl;
    	delete ptr;
    }
    
    template< typename T >
    T smartPointer< T >::operator *( ) const
    {
    	return *ptr;
    }
    
    template< typename T >
    T* smartPointer< T >::operator ->( ) const
    {
    	return ptr;
    }
    

    Meine Main:

    #include <windows.h>
    #include <iostream>
    
    #include "SmartPointer.h"
    #include "SmartPointer.cpp"
    
    using namespace std;
    
    class MYTESTCLASS
    {
    public:
    	MYTESTCLASS( )
    	{
    	}
    	~MYTESTCLASS( )
    	{
    	}
    	void Aus( )
    	{
    		cout << "Ich bin aus MYTESTCLASS !" << endl;
    	}
    };
    
    int main( int arg, char* arvg[ ] )
    {
    	smartPointer< MYTESTCLASS > xc( new MYTESTCLASS );
    	xc->Aus( );
    	{
    		smartPointer< MYTESTCLASS > xx( xc );
    		xx->Aus( );
    	}
    	xc->Aus( );
    	return NULL;
    }
    

    Nun meine Frage: Warum wird der letzt Call vor dem return NULL; noch ausgeführt? In der Console steht davor auch DESTROYED. Kann mir das jemand mal erklären?

    MfG



  • Zu diesem Zeitpunkt ist nur der innere Smart-Pointer zerstört worden, der äussere lebt bis Ende main() . Da du aber keinen Kopierkonstruktor definiert hast, führen Kopien zu undefiniertem Verhalten (da der Speicher zweifach freigegeben wird).

    In deinem Code könnte man einiges verbessern, hier ein paar Vorschläge:

    • Bezeichner mit Unterstrichen am Anfang, wie __SMARTPOINTER_H__ , sind für Compiler und Implementierung reserviert. Verwende doch SMARTPOINTER_H .
    • Benutze im Konstruktor die Initialisierungsliste statt Zuweisungen.
    • Verbiete Kopierkonstruktor und Zuweisungsoperator, indem du sie private machst. Oder implementiere sie sinnvoll.
    • Mache den Konstruktor, der ein T* nimmt, explicit , um implizite Konvertierungen von Zeigern zu verhindern.
    • NULL steht für den Nullpointer. Missbrauche das Literal nicht für int s, schreibe return 0; oder gar nichts.
    • Du benötigst kein <windows.h> .
    • Defaultkonstruktor und Destruktor mit leerer Definition werden automatisch vom Compiler generiert, du brauchst sie nicht hinzuschreiben.
    • #endif __SMARTPOINTER_H__ ist kein gültiges C++. Du kannst aber SMARTPOINTER_H als Kommentar einsetzen.
    • .cpp-Dateien solltest du nie inkludieren.
    • Templatedefinitionen müssen im Header stehen. Du kannst allerdings eine separate .inl-Datei für die Implementierung verwenden und am Schluss des Schnittstellen-Headers einbinden.
    • Wenn du std::cout schon im Template benötigst, solltest du <iostream> auch bereits dort einbinden. Sonst muss der Benutzer des Templates daran denken, damit der Code kompiliert.


  • Wow. Vielen dank. Hab einiges ausgebessert!
    Wie müsste ich das mit dem Kopierkonstruktor anstellen?

    MfG



  • BlauBär schrieb:

    Wow. Vielen dank. Hab einiges ausgebessert!
    Wie müsste ich das mit dem Kopierkonstruktor anstellen?

    MfG

    Im Idealfall verbietest du Kopien, da das meist nicht gewünscht ist. Move-Konstruktor hingegen ist ein heißer Tipp.

    template< typename T >
    class smartPointer
    {
      ...
    
      // Kopien verbieten.
      smartPointer(smartPointer<T> const&) = delete;
      smartPointer<T>& operator=(smartPointer<T> const&) = delete;
    
      smartPointer(smartPointer<T>&& other)
        : ptr(other.ptr)
      {
        other.ptr = 0;
      }
      smartPointer<T>& operator=(smartPointer<T>&& other)
      {
        if(ptr == other.m_ptr)
        {
          other.ptr = 0;
        }
        else
        {
          delete ptr;
          ptr = other.ptr;
          other.ptr = 0;
        }
    
        return *this;
      }
    
      ...
    };
    

    So ungefähr. Keine Garantie, bin gerade etwas breit. ,)


Log in to reply