smart pointer: überladen von -> Operator



  • Hallo zusammen!

    Ich bin dabei ein smart pointer Klassentemplate zu schreiben. Jetzt frage ich mich aber: Wie kann ich den -> Operator überladen dass, wenn der smart pointer auf eine Struktur zeigt, man direkt auf die Strukturmember zugreifen kann?
    Also sowas:

    struct S
    {
        int x, y;
    };
    
    int main()
    {
    
        S obj;
    
        Pointer<s> p(obj);
    
        p->x = 100;
    
    }
    

    Ist das überhaupt möglich?

    template <typename T>
    class Pointer
    {
    
    	T *m_ptr;
    	unsigned long *m_count;
    
    	public:
    		Pointer(const T &obj)
    		{
    			m_ptr = new T(obj);
    			m_count = new unsigned long(1);
    		}
    
    		~Pointer()
    		{
    			--*m_count;
    
    			if(*m_count == 0)
    			{
    				delete m_ptr;
    			}
    		}
    
    		Pointer(const Pointer &p)
    		{
    			m_ptr = p.m_ptr;
    			m_count = p.m_count;
    			++*m_count;
    		}
    
    		Pointer& operator = (const Pointer &p)
    		{
    			if(p != *this)
    			{
    				~Pointer();
    				m_ptr = p.m_ptr;
    				m_count = p.m_count;
    				++m_count;
    			}
    
    			return *this;
    		}
    
    		T& operator * ()
    		{
    			return *m_ptr;
    		}
    };
    


  • Hallo

    Sollte so aussehen

    T& operator -> ()
    {
      return *m_ptr;
    } 
    const T& operator -> () const
    {
      return *m_ptr;
    }
    

    bis bald
    akari



  • Ich hab's doch noch gefunden. So macht man's:

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

    Danke trotzdem.


  • Mod

    akari schrieb:

    Hallo

    Sollte so aussehen

    T& operator -> ()
    {
      return *m_ptr;
    } 
    const T& operator -> () const
    {
      return *m_ptr;
    }
    

    bis bald
    akari

    Das hätte Endlosrekursion zur Folge.

    Stöffel schrieb:

    Hallo zusammen!

    Ich bin dabei ein smart pointer Klassentemplate zu schreiben. Jetzt frage ich mich aber: Wie kann ich den -> Operator überladen dass, wenn der smart pointer auf eine Struktur zeigt, man direkt auf die Strukturmember zugreifen kann?
    Also sowas:

    struct S
    {
        int x, y;
    };
    
    int main()
    {
    
        S obj;
    
        Pointer<s> p(obj);
    
        p->x = 100;
    
    }
    

    Ist das überhaupt möglich?

    template <typename T>
    class Pointer
    {
    
    	T *m_ptr;
    	unsigned long *m_count;
    	
    	public:
    		Pointer(const T &obj)
    		{
    			m_ptr = new T(obj);
    			m_count = new unsigned long(1);
    		}
    		
    		~Pointer()
    		{
    			--*m_count;
    			
    			if(*m_count == 0)
    			{
    				delete m_ptr;
    			}
    		}
    		
    		Pointer(const Pointer &p)
    		{
    			m_ptr = p.m_ptr;
    			m_count = p.m_count;
    			++*m_count;
    		}
    		
    		Pointer& operator = (const Pointer &p)
    		{
    			if(p != *this)
    			{
    				~Pointer();
    				m_ptr = p.m_ptr;
    				m_count = p.m_count;
    				++m_count;
    			}
    			
    			return *this;
    		}
    		
    		T& operator * ()
    		{
    			return *m_ptr;
    		}
    };
    

    Um das Verhalten des Operators -> für Klassenobjekte zu verstehen, muss man zunächst den Mechanismus des eingebauten Operators für Zeiger begreifen. Das Ergebnis der Anwendung des eingebauten Operators ist ein Ausdruck, der nur auf eine einzige Weise verwendet werden kann: durch Benutzung mit einem Bezeichner eines Klassenmembers. Wesentlich daran ist, dass dieses Etwas kein Objekt ist und auch keinen Typ hat (Ganz analog zum Operator ->*, dieser hat aber zwei Parameter) - das bedeutet auch, dass dieses Etwas nicht unmittelbar das Ergebnis eines überladenen Operators -> sein kann, mithin das Verhalten des eingebauten Operators nicht unmittelbar nachvollzogen werden kann. Deshalb benutzt der Standard hier ein wenig 'Magie' - Auf das Ergebnis eines überladenen Operators -> wird wiederum dieser Operator aufgerufen - solange, bis jenes Ergebnis irgendwann ein Pointer ist und die eingebaute Semantik greift. Eine einzige Verwendung des Operators -> kann daher eine große Zahl von Funktionsaufrufen implizieren. Richtigerweise sollte die Überladung daher so aussehen:

    T* operator->() const
    {
        return m_ptr;
    }
    

    constness des Pointers und constness des Pointees sind üblicherweise nicht identisch.
    Auf schwerwiegende Defizite des restlichen Codes kann auch jemand anderes hinweisen.



  • Schwerwiegende Defizite? In meinem Code? 🤡


Anmelden zum Antworten