WinApi Funktion in C++ "aendern"


  • Mod

    Benutz doch in solchen Beispielen konsequent die Smartpointer. So wie jetzt ist es doch bloß C mit new statt malloc und der Threadersteller fragt sich, wo überhaupt der Unterschied zwischen den Sprachen ist.



  • Ja, Sire! Sofort Sire!

    unique_ptr<IP_ADAPTER_ADDRESSES>
    get_adapters_addresses(ULONG family, ULONG flags) {
      using ptr_t = std::unique_ptr<IP_ADAPTER_ADDRESSES>;
      ULONG size = 15*1024;  // lt. doku
      auto addr = ptr_t{(PIP_ADAPTER_ADDRESSES)new char[size]};
      ULONG rc;
      while((rc=GetAdapterAddresses(family, flags, nullptr, addr.get(), &size))==ERROR_BUFFER_OVERFLOW)
        addr=ptr_t{(PIP_ADAPTER_ADDRESSES)new char[size]};
      if(rc==ERROR_SUCCESS)
        return addr;
      // Hier koennte Ihre Fehlerbehandlung stehen...
      switch(rc){
      case ERROR_NOT_ENOUGH_MEMORY:
        throw bad_alloc{};
      // ....
      default:
        throw runtime_error{"What the zuny!?"};
      }
    }
    

    @c_to_cpp: wie Du siehst sind nach SeppJs Einwand und einer weiteren Iteration des Codes alle händischen Speicherfreigaben verschwunden. Der Code ist kürzer und klarer.



  • @c_to_cpp
    Arbeite erstmal mit malloc/free, ist für den Anfang das einfachste.

    @Furble Wurble
    Darf man denn überhaupt ein mit new char[] besorgtes char-Array mit delete (POD_TYPE*)addressOfFirstElement freigeben?
    Wenn nicht, was ich vermute, dann bekommt man mit unique_ptr<POD_TYPE> ein bisschen ein UB Problem.
    Ich hab' das bisher immer mit malloc + shared_ptr<POD_TYPE> + custom deleter der free aufruft gemacht.

    (Man kann natürlich auch nen unique_ptr<POD_TYPE, CLibFreeDeleter> o.ä. verwenden. Wenn man vorwiegend auto verwendet ist das OK, aber sonst... bäh.)

    ps.: So:

    #include <memory>
    #include <cassert>
    
    template <class T>
    std::shared_ptr<T> AllocateSizedPod(size_t size)
    {
        assert(size >= sizeof(T));
        std::shared_ptr<T> const ptr(static_cast<T*>(std::calloc(1, size)), std::free);
        if (!ptr)
            throw std::bad_alloc();
    
        return ptr;
    }
    


  • hustbaer schrieb:

    @Furble Wurble
    Darf man denn überhaupt ....

    Nein. Das ist mir auch aufgefallen - sonst würde ich auch schon pofen. 😞

    Tatsächlich stimme ich Dir zu malloc/free ist einfacher korrekt hinzubekommen, als new/delete.

    Ich bastel gerade noch an einem wrapper, aber der nimmt einen vector<char> als Speicher...ist aber nur für mich, damit ich gleich schlafen kann. Ohne schlechtes Gewissen... 🙂



  • Nimm new und delete, das macht es noch leichter!
    ~ Furble Wurble

    Ich <- doof!

    Mal eben so aus dem Lamäng einen Code hinpfuschen...Nie wieder! 🕶



  • Danke erstmal. Der Wrapper von Furble wäre evtl. noch interessant... ?
    Ich werde es erstmal bei malloc / free belassen. Habe noch 2 Fragen :

    1. Wenn ich das ganze mit den Smart_Pointern usw. weglasse (Habe mich damit noch zuwenig befasst) müsste folgender Code aber gehen oder ?
    PIP_ADAPTER_ADDRESSES addr = (PIP_ADAPTER_ADDRESSES)new char[size];
    
    while((rc=GetAdapterAddresses(family, flags, nullptr, addr, &size)==ERROR_BUFFER_OVERFLOW){
       delete[]addr; 
       addr=(PIP_ADAPTER_ADDRESSES)new char[size]; 
    }
    

    Hier müsste ja wie im Original code nach dem 1. Aufruf (wenn dieser denn Failt) die "neue" Speichergroesse angefordert werden. Kann es hier ein Problem geben ? Ich weiß nicht ob GetAdapterAdresses addr evtl. ändert, ich würde den dann noch wegspeichern davor , damit delete wieder den Originalpointer erhält?

    2.)
    auf der MSDN Seite ( Google: site:msdn.microsoft.com https://msdn.microsoft.com/de-de/library/windows/desktop/aa366314%28v=vs.85%29.aspx )

    wird der Speicher so freigegeben ... ??? :

    //6.Free any memory allocated for the pAdapterInfo structure.

    if (pAdapterInfo)
            free(pAdapterInfo);
    

    ==>> pAdapterInfo ist doch eigentlich ne Linked-List, ist das Speicherfreigeben so nicht falsch ? Der gibt doch nur für ein Element frei ? ? ?



  • c_to_cpp schrieb:

    Ich weiß nicht ob GetAdapterAdresses addr evtl. ändert, ich würde den dann noch wegspeichern davor, damit delete wieder den Originalpointer erhält?

    GetAdaptersAddresses() kann den Wert (die Adresse auf die der Zeiger zeigt) des Parameters AdapterAddresses nicht ändern, da er per value übergeben wird.

    c_to_cpp schrieb:

    ==>> pAdapterInfo ist doch eigentlich ne Linked-List, ist das Speicherfreigeben so nicht falsch ? Der gibt doch nur für ein Element frei ? ? ?

    Das delete[] gibt allen Speicher frei, den du mit new T[N] angefordert hast. IP_ADAPTER_ADDRESSES ist zwar eine linked list, "lebt" aber nur in dem von dir bereitgestelltem Speicher. Eine Liste ist es deshalb, weil die einzelnen IP_ADAPTER_ADDRESSES unterschiedlich groß sein können. Du hättest sonst keine Möglichkeit festzustellen, wo ein IP_ADAPTER_ADDRESSES endet und ein neues anfängt.



  • Wenn man die PIP_ADAPTER_ADDRESSES nur lokal braucht kann man das auch ganz ohne Pointer per std::vector<char> lösen (ohne Sicherheitsgurte und Helm):

    #include <vector>
    
    void f()
    {
       ULONG RequiredSize = 0;
       ::GetAdaptersAddresses( AF_INET, 0, NULL, NULL, &RequiredSize );
       if( RequiredSize > 0 )
       {
          std::vector<char> Buffer( RequiredSize );
          PIP_ADAPTER_ADDRESSES Addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>( &Buffer[0] );
    
          ::GetAdaptersAddresses( AF_INET, 0, NULL, Addresses, RequiredSize );
       }
    }
    


  • GetAdaptersAddresses() kann den Wert (die Adresse auf die der Zeiger zeigt) des Parameters AdapterAddresses nicht ändern, da er per value übergeben wird.

    Stimmt, peinlich.
    Ok, dann müsste das mit meinen paar Zeilen eigentlich funktionieren...


  • Mod

    c_to_cpp schrieb:

    GetAdaptersAddresses() kann den Wert (die Adresse auf die der Zeiger zeigt) des Parameters AdapterAddresses nicht ändern, da er per value übergeben wird.

    Stimmt, peinlich.
    Ok, dann müsste das mit meinen paar Zeilen eigentlich funktionieren...

    Bloß, dass man dann eben im Falle einer Exception ein Problem hat.



  • c_to_cpp schrieb:

    Danke erstmal. Der Wrapper von Furble wäre evtl. noch interessant... ?

    Na klar. Ich habe ja gerade eine richtige Serie von guten Ideen in diesem Thread 🙂
    So habe ich mir das minimal gedacht:

    template<typename T>
    class wrapper : private vector<char> {
      using impl_t = vector<char>;
    public:
      using pointer = T;
      using impl_t::resize;
      wrapper() = default;
      wrapper(size_t sz)
        : impl_t(sz) { }
      pointer get() { return reinterpret_cast<pointer>(&(*this)[0]); }
    };
    
    using pip_adapter_addresses = wrapper<PIP_ADAPTER_ADDRESSES>;
    
    pip_adapter_addresses
    get_adapters_addresses(ULONG family, ULONG flags) {
      ULONG size = 15*1024;  // lt. doku
      pip_adapter_addresses addr(size);
      ULONG rc;
      while((rc=GetAdaptersAddresses(family, flags, nullptr, addr.get(), &size))==ERROR_BUFFER_OVERFLOW)
        addr.resize(size);
      if(rc==ERROR_SUCCESS)
        return addr;
      // Hier koennte Ihre Fehlerbehandlung stehen...
      switch(rc){
      case ERROR_NOT_ENOUGH_MEMORY:
        throw bad_alloc{};
      // ....
      default:
        throw runtime_error{"What the zuny!?"};
      }
    }
    


  • DocShoe schrieb:

    [...]

    yay! 👍 😋


Anmelden zum Antworten