Wann ein Zeiger als Parameter wann eine Referenz?



  • DrGreenthumb schrieb:

    Das war so das, was mir als erstes in den Sinn kam, bis ich darüber nachgedacht habe und mir auch kein Beispiel eingefallen ist.

    endlich mal einer, der es tut! der herr sei gepriesen!

    und ich leiere wiedermal meinen text runter...

    an sich ist es dem compiler egal, ob zeiger oder ref. refs haben zwei technische vorteilchen.
    a) da sie nicht auf 0 zeigen können, kann es situationen geben, wo der optimierer besser optimieren kann. wichtigkeit: null. die compiler verlassen sich nach dem ersten zugriff auch so drauf, daß da nicht 0 drin ist (sonst wär ja ne schutzverletzung gefogen). und strengere optimierungstips, wie ein ASSERT/__assume__ kann man selber setzen. übrigens würde das ASSERT ne qualifizierte fehlermeldung geben statt nur UB zu erzeugen.
    b) dokumentation im sinne von "Hier darf 0 übergeben werden" gegen "Hier darf nicht 0 übergeben werden".
    wer das allen erstes erst nehmen würde, müßte schreiben:
    int strcmp(char& a,char& b)
    den strcmp verträgt keine übergebenen nullen. viel zu viel code ist in dieser hinsicht inkonsistent.
    strenge verfechter müßten sogar statt des pimpl-idioms ein rimpl-idiom fahren (und das ist in der tat in diesem forum mal passiert). wie sie allerdings es schaffen wollen, smart references zu coden, weiß ich noch nicht.
    klingt nach schwachsinn? isses auch.

    refs haben ne existenzberechtgung! als parameter des copy-ctors und als rückgaben des zuweisungsoperators und konsorten. es war einfach notwendig, refs zu erfinden, damit c++ klappt. und wir sollten die refst auch aufs notwendige beschränken. denn refs sind refs und zeiger sind zeiger. mit unterschiedlicher bedeutung.
    rein technisch kann unsere sprache nur call-ba-value. und das ist gut so. soper sogar.
    hab ich irgendwo nen fehler in meinem code, äußert sich der doch eigentlich immer, indem ne variable nen falschen wert hat. in meinem op[] zum beispiel fliegt ein ASSERT und ich muss jetzt feststellen, welcher aufrufer da nen falschen wert reintat, welcher aufrufer des aufrufers in den aufrufer,... bis ich den finde, der nen richtigen wert bekam aber nen falschen wert weitergab. und dann gucke ich innerhalb der funktion, was passiert ist. ich weiß ohne referenzparameter eines sicher:
    meine var kann nur zerstört worden sein, wenn sie mit & als funktionsparameter verwendet wurde oder wenn sie links von nem = stand. da ich mich gerade dafür interessiere, wie meine variable kaputtgegangen sein kann, freue ich mich wie ein schneekönig, daß ich mit dieser einfachen regel in sekunden alle verdächtigen stellen lokalisiert habe. ganz ohne nachdenken. das ist einfach geil.
    jo, und diese sichweise wird von const-refs gar nicht gestört. die machen ja auch den übergebenen wert nicht kaputt. es sind sozusagen call-by-value-dinge.

    das bringt mich zur regel: meide refs, außer, es sind const-refs. benutze non-const-refs nur, wenn es echt notwendig ist.
    fehlersuchzeit wird's danken.



  • volkard schrieb:

    benutze non-const-refs nur, wenn es echt notwendig ist.
    fehlersuchzeit wird's danken.

    Kannst du dafür mal ein beispielgeben, bitte?



  • Shade Of Mine schrieb:

    volkard schrieb:

    benutze non-const-refs nur, wenn es echt notwendig ist.
    fehlersuchzeit wird's danken.

    Kannst du dafür mal ein beispielgeben, bitte?

    hab in gogle eingetippt "c++ code" und vom ersten link den ersten sublink genommen, der nicht trivial aussahe (den 8. überhaupt).

    STDMETHODIMP COLTools::OnWriteComplete(IExchExtCallback        *lpExchangeCallback,
                                            ULONG                    ulFlags)
    {
       AFX_MANAGE_STATE(AfxGetStaticModuleState());
       if (m_bSubmittingMessage)
       {
          try
          {
             char szTempFolder[MAX_PATH] = {0};
        GetTempPath(MAX_PATH, szTempFolder);
        :
        // Ask Outlook for the message
        if ((SUCCEEDED(lpExchangeCallback->GetObject(&lpMdb, (LPMAPIPROP *)&lpMessage)))&&
            (lpMessage))
        {
           CComPtr <IMAPITable>    pAttachTablePtr;
           // Get the table of attachments
           if (SUCCEEDED(hRet=lpMessage->GetAttachmentTable(0, &pAttachTablePtr)))
           {
              // Enumerate all the attachments
              CSimpleArray<CAttachment*> cAttachments;
              :
              hRet = HrQueryAllRows(pAttachTablePtr, (LPSPropTagArray)&tags, NULL, NULL, 0, &pRows);
              ULONG ulRowsMax = pRows->cRows;
              for (ULONG uldx=0;uldx<ulRowsMax;uldx++)
              {
            :
            // Open the attachment and store it in an array
            hRet = lpMessage->OpenAttach(ulAttachment, &IID_IAttachment, MAPI_BEST_ACCESS, &pAttachPtr);
            if (SUCCEEDED(hRet))
            {
               CAttachment *pAttachment = new CAttachment(pAttachPtr,ulMethod,FALSE, csFileName, csLongFileName);
               if (pAttachment)
               {
                  pAttachment->SetAttachNum(ulAttachment);
                  cAttachments.Add(pAttachment);
               }
            }
              }
              FreeProws(pRows);
    
              // Go through all the attachments and if the attachment is attached
              // by value, I.e. it's not a link to a fileserver, nor an embedded object (message, image...)
              // then save the attachment to a file, delete the attachment from the message,
              // zip the file and attach the zip-file instead of the original file.
              for(int ndx=0;ndx<cAttachments.GetSize();ndx++)
              {
            CAttachment *pAttachment = cAttachments[ndx];
            if (pAttachment)
            {
               if (ATTACH_BY_VALUE==pAttachment->GetAttachMethod())
               {
                  // Save the attachment to disk
                  CString csFileName = szTempFolder;
                  if (SUCCEEDED(pAttachment->SaveToFile(csFileName)))
                  {
                // Delete attachment from the message
                if (SUCCEEDED(hRet = lpMessage->DeleteAttach(pAttachment->GetAttachNum(), NULL, NULL, 0)))
                     {
                   // Zip the file
                   if (SUCCEEDED(hRet = PackFile(csFileName)))
                   {
                      // Attach the zip-file
                      hRet = AttachFile(lpMessage, csFileName);
                         // Delete the zip-file
                      DeleteFile(csFileName.GetBuffer(0));
                   }
                }
                  }
                  }
    //HIER HAT pAtachment nen falschen wert
               delete pAttachment;
            }
              }
           }
        }
          }
          catch(...)
          {
          }
          // Reset the flag
          m_bSubmittingMessage = FALSE;
       }
       return S_FALSE;
    }
    

    nimm an, an der bezeichneten stelle habe pAttachment nen falschen wert. wie man seht, benutzt der autor lauter microsoft-code. der benutzt keine referenzen. wie geil. ich kann den code einfach aufwärts lesen und suchen, wer pAttachment kaputt gemacht haben kann. keiner! also stand schon in cAttachments[ndx] quark drin.
    mach das mal, wenn die leutchen ständig non-const-refs benutzen. da wirste innerhalb von tagen doch durchdrehen.



  • Da die "kritsche" Stelle schon mit

    CAttachment *pAttachment = cAttachments[ndx];
    if (pAttachment)
    

    ist das kein besonders geeignetes Beispiel für dein Argument (Pointer <-> Referenz) wie ich finde, da ein möglicher Null-Pointer die Verwendung von Referenzen an dieser Stelle weitestgehend ausschliesst. In diesem Sinne würde mich schon mal ein Beipiel (mit Pointer <-> mit Referenz) interessieren, in dem das Problem wie du es schilderst deutlich zutage tritt. Mir ist das nämlich auch nicht so ganz klar 😕

    mfg JJ



  • ok, schlechtes beispiel. dann muss ich wohl länger suchen.
    wie sucht man gezielt schlechten code?



  • wie sucht man gezielt schlechten code?

    na, hier im forum! 😃 😉



  • volkard schrieb:

    wie sucht man gezielt schlechten code?

    Such nach MFC oder WinApi Sources... 😃



  • Such nach "Spiele". Da gibt's genug Leute, die nicht coden können, aber Spiele machen wollen. 🤡



  • Optimizer schrieb:

    Such nach "Spiele". Da gibt's genug Leute, die nicht coden können, aber Spiele machen wollen. 🤡

    jo, war auch mein gedanke. hab sofort zerbies code angeguckt. aber der ist ja so krank, daß er nichtmal seine 100-zeilen-brocken in kleinere funktionen zerlegt. war nicht verwertbar.



  • roflmao. 😃



  • kann von hier aus nix suchen. die connection bricht immer nach ner minute ab. ich kann nur versuchen, das nächste ma, wenn ich code finde, der deutlich davn profitiert, ihn euch mitzubringen.



  • @Volkrad:

    im Thread: http://www.c-plusplus.net/forum/viewtopic.php?t=81443 hast du eine Variante einer Funktion geschreiben, die der vorherigen entspricht, allerdings einen ostream entgegennimmt, damit man felxibler ist.
    Wieso nimmst ud ihn als non-const-ref entgegen.

    De Regel lautet doch

    benutze non-const-refs nur, wenn es echt notwendig ist.



  • rofl 😃 😃 😃



  • nicht wirklich flexibler. in der hauptsache kaputter.
    warum verwende ich std::swap?
    aus historischen gründen.



  • Hab zwar keine Ahnung wo man im Netz miesen Code findet aber richtig guten Source findet man hier ~~> http://www.tw.ioccc.org/years.html#2000_anderson 😃



  • Das erklärt immernoch nciht, warum du jetzt den ostream als nicht konstante Referenz entgegennimmst und somit gegen deine eigene Regel verstößt.



  • volkard schrieb:

    mach das mal, wenn die leutchen ständig non-const-refs benutzen. da wirste innerhalb von tagen doch durchdrehen.

    Sorry, Missverständnis.

    Ich weiss, dass du Zeiger gerne nimmst. Ich wollte nur wissen, wann du denn dann non const Referenzen nimmst.



  • Helium schrieb:

    Das erklärt immernoch nciht, warum du jetzt den ostream als nicht konstante Referenz entgegennimmst und somit gegen deine eigene Regel verstößt.

    und du hast nicht über meine antwort nachgedacht.
    warum verwende ich std::swap? aus historischen gründen. das ding hat sich in dieser form fest eingebürgert, bevor man erkannte, wie falsch es eigentlich ist. und das gleiche passierte anno dazumal mit virtual void Foo::printAt(ostream& out);. afair sah ich es 1995 beim borland c++ 3.1 in der lib zum ersten mal. das ändert sich nicht von heut' auf morgen. eventuell ändert sich das nie und dan läßt sich es auch mit ein paar ausnahmen leben. aber man muß es ja nicht drauf anlegen, und in völliug anderen zusammenhängen proggen wie die leutchen damals vor 10 jahren.



  • Shade Of Mine schrieb:

    Ich weiss, dass du Zeiger gerne nimmst. Ich wollte nur wissen, wann du denn dann non const Referenzen nimmst.

    kann mich gerade nur an swap und printAt erinnern. evtl immer bei streams. ob technische argumente dafürsprechen? vielleicht. sie werden auf jeden fall vom argument verdeckt, daß man in seinem code einigermaßen konsistent zum rest der welt baen muß. wenigstens bei swap kommt man nicht drumherum. wegen der neuen implementierung von op= mit dem swap-trick.
    und halt, wo es sein muß. also operatoren.
    refs als member habe ich nie. da hakt's bei mir dann einfach aus, daß ich ne ref als member habe, die meine klasse ganz zufällig genau sizeof(void*) bytes größer werden läßt.



  • Ist es nicht immer lästig bei Zeigern zu prüfen, ob sie 0 sind, bevor man sie dereferenziert?


Anmelden zum Antworten