Zeiger "vernichtet" sich selbst?



  • Einen wunderschönen guten Morgen zusammen 🙂 ,

    vorneweg: es kann gut sein, das dieses Problem recht trivial ist und es hier schon einige Lösungen gibt - ich habe keine gefunden, also bitte nicht haun wenn das schon der 15. Beitrag von dieser Sorte ist.

    Mein Code sieht (stark vereinfacht) so aus:

    public ref class MyClass
    {
    	private:
    		MyExternalClass *pointer;
    
    	public:
    		MyClass()
    		{
    			pointer = createMyExternalClass();
    		}
    
    		void foo()
    		{
    			pointer->bar();
    		}
    };
    

    Die Klasse besitzt weder Finalisierer noch Destruktor noch ein Dispose.
    MyExternalClass ist eine abstrakte Klasse von der mittels createMyExternalClass() eine Instanz erzeugt werden kann (beides natives C++).

    Folgender Code führt in Zeile 2 zu einer NullReferenceException:

    MyClass^ c = gcnew MyClass();
    c->foo();
    

    Nach dem Ablauf des Konstruktors wird pointer auf null gesetzt - obwohl der Zeiger ja ohne GC erzeugt wurde und keine Methode meiner Klasse das tun würde.

    Ich hoffe einer von euch weiß da Rat - Ich bin zwar C# und C++-Veteran, aber bei C++/CLI absoluter Newbie.

    Danke!
    trion



  • Hab gerade mal auf die schnelle das hier getestet, geht ohne Probleme.

    Bist du sicher, dass das Problem nicht irgendwo anders liegt ?

    #include "stdafx.h"
    
    using namespace System;
    
    class UnmanagedBase
    {
    public:
      virtual ~UnmanagedBase() {}
    
      virtual int foo() = 0;
    };
    
    class UnmanagedImp : public UnmanagedBase
    {
    private:
      int m_n;
    public:
      UnmanagedImp()
      {
        m_n = 42;
      }
    
      int foo()
      {
        return m_n;
      }
    };
    
    public ref class Managed
    {
    private:
      UnmanagedBase *m_pUnmanaged;
    
    public:
    
      Managed()
      {
        m_pUnmanaged = new UnmanagedImp;
      }
    
      ~Managed()
      {
        delete m_pUnmanaged;
      }
    
      int foo()
      {
        return m_pUnmanaged->foo();
      }
    };
    
    int main(array<System::String ^> ^args)
    {
      Managed ^m = gcnew Managed;
    
      Console::WriteLine(m->foo().ToString());
    
      return 0;
    }
    


  • Danke für die Antwort.

    Stimmt, du hast recht, das Problem war wirklich woanders:
    Der Konstruktor ist überladen und ich hab die Überladung aufgerufen, die den ersten Konstruktor aufruft - der äußere killt dann den Zeiger, weil er ihn initialisiern will.

    Ich dachte das funktioniert so:

    MyClass(int arg1, int arg2, int arg3, int arg4)
    {
    	foo(arg1, arg2, arg3, arg4);
    }
    
    MyClass(int arg1, int arg2)
    {
    	MyClass(arg1, arg2, 1337, 42);
    }
    

    Gibt es eine Möglichkeit, das so umzuschreiben, dass der äußere Konstruktor die Variablen nicht "nochmal" initialisiert?



  • Ja, initialisierungs code auslagern (z.B. void init()) und dann in den jeweiligen konstruktoren init() aufrufen.

    Simon



  • Ich hatte zwar gehofft das geht eleganter, aber nun werde ich das wohl so machen.

    Danke!



  • Ich kenne mich mit C++/CLI nicht wirklich aus, aber in C# gibt es folgende Möglichkeit:

    MyClass(int arg1, int arg2, int arg3, int arg4)
    {
        foo(arg1, arg2, arg3, arg4);
    }
    
    MyClass(int arg1, int arg2) : this(arg1, arg2, 1337, 42)
    {
    }
    

    Vielleicht gibt es ja etwas Ähnliches in C++/CLI.


Anmelden zum Antworten