The secret of while( int i = getValue() )



  • Hi,

    wenn ich eine Variable in einem if/while/etc. - Statment definiere muss man ja auch direkt ne Zuweisung vornehmen.

    while( int i = getValue() ) use i ;
    

    Da dies gültig ist, muss ja der Ausdruck int i = getValue() einen Wert zurück geben der in bool konvertierbar ist, in dem Fall sich selber.

    Die Frage ist nun, als was für nen Typ er sich selbst zurück gibt. Als Referenz oder Rvalue oder etc. ...
    Denn folgendes zB funktioniert nicht mehr:

    while( (int i = getValue()) == 2 ) use i ;
    

    Was läuft da wirklich ab ?


  • Mod

    int i = getValue()
    

    ist kein Ausdruck sondern eine Definition. Es kann somit nicht Teil eines anderen Ausdrucks sein und es ist weder ein lvalue noch ein rvalue. Mithin ist

    (int i = getValue()) == 2
    

    in jedem Fall fehlerhaft.
    Nur für Zwecke der Bestimmung, wann Destruktoren temporärer Objekte ausgeführt werden, zählen solche Definitionen (ebenso wie ganz normal platzierte Definitionen) als "vollständige Ausdrücke".



  • Hmm, so ganz verstanden habe ich das irgendwie noch nicht.

    Eine Definition in der if-Bedingung muss doch irgendeinen Wert haben. Sonst kann es doch gar nicht ausgewertet werden.

    Wieso kann ich dann mit diesem Wert keine anderen Operationen durchführen.

    😕



  • Hallo,

    vielleicht kann man es besser so ausdrücken: eine Bedingung, die als Definition formuliert ist, hat als Wert den Wert der implizit in bool konvertierten Variable, die in der Bedingung definiert wurde.

    Das ändert aber nichts daran, dass es hier eine Definition bleibt, und somit nicht Teil eines Ausdrucks sein kann.

    MfG,

    Probe-Nutzer



  • Kann man ganz tolle Sachen mit machen:

    while(char *p = new char[1024]) cout << "Ein Kilobyte passt noch..." << endl;
    cout << "Passt nicht mehr..." << endl;
    

    EDIT:
    Oder auch nicht...
    Sollte new nicht 0 zurückgeben wenn kein Platz mehr ist?



  • Fellhuhn schrieb:

    Sollte new nicht 0 zurückgeben wenn kein Platz mehr ist?

    nein, bad_alloc werfen.

    aber new wird nicht fehlschlagen...


  • Administrator

    Fellhuhn schrieb:

    EDIT:
    Oder auch nicht...
    Sollte new nicht 0 zurückgeben wenn kein Platz mehr ist?

    Diese Funktionalität erreichst du nur mit nothrow .

    #include <new> // nothrow
    
    int main()
    {
      char* p = new (std::nothrow) char[1024];
    
      // Wenn es keinen Speicher mehr hatte, ist p == 0.
    
      return 0;
    }
    

    Ansonsten wird, wie Shade Of Mine gesagt hat, bad_alloc geworfen.

    Grüssli



  • Shade Of Mine schrieb:

    aber new wird nicht fehlschlagen...

    Warum nicht?



  • Nexus schrieb:

    Shade Of Mine schrieb:

    aber new wird nicht fehlschlagen...

    Warum nicht?

    moderne systeme machen lazy memory commit - sprich sie allokieren den speicher erst dann wenn du ihn brauchst (nicht wenn du sagst dass du ihn haben willst).

    ergo gibt es praktisch nur dann ein new fehler wenn das system gerade dabei ist den swap bereich zu vergroessern. das und natuerlich ungueltige groessen angaben sind die einzigen situationen wo moderne systeme new fehlschlagen lassen.


  • Administrator

    Shade Of Mine schrieb:

    moderne systeme machen lazy memory commit - sprich sie allokieren den speicher erst dann wenn du ihn brauchst (nicht wenn du sagst dass du ihn haben willst).

    Was verstehst du unter moderne Systeme? WinXP SP3 gehört da wohl nicht dazu? Der folgende Code führt bei mir ziemlich schnell zu einem bad_alloc:

    int main()
    {
      for(;;)
      {
        new int[100000000];
      }
    
      return 0;
    }
    

    Oder hab ich an deiner Erklärung etwas missverstanden?

    Grüssli



  • Dravere schrieb:

    Der folgende Code führt bei mir ziemlich schnell zu einem bad_alloc:

    int main()
    {
      for(;;)
      {
        new int[100000000];
      }
    
      return 0;
    }
    

    Oder hab ich an deiner Erklärung etwas missverstanden?

    Shade Of Mine schrieb:

    das und natuerlich ungueltige groessen angaben sind die einzigen situationen wo moderne systeme new fehlschlagen lassen.

    😉



  • Nein, Lazy Commit wird verwendet, aber bei einigen Einstellungen wird die allokierte Page durch einen schreibzugriff zwingend commitet. zB bei Buffer Overflow Checks und dergleichen.

    Teste mal folgenden Code:

    #include<stdlib.h>
    
    int main() {
    	int i=0;
    	void* p;
    	while(p=malloc(1024)) {
    		++i;
    	}
    	return i;
    }
    

    Da hast du keine moeglichen Probleme mit default Ctors und aehnlichen schreibzugriffe.

    Konnte das zumindest gerade unter Ubuntu und Vista wieder bestaetigen dass das verhalten immernoch so ist...


  • Administrator

    @CodeFinder,
    Das ist aber eine gültige Grössenangabe. Zähle ruhig nochmals die Nullen nach 😉

    @Shade Of Mine,
    Also zum einen ging es ja ursprünglich um ein anderes Beispiel, welches angeblich nie abbrechen tut. Aber auch dieser von dir präsentierter Code, bricht bei mir ab: VS 8 SP1, WinXP SP3

    Grüssli



  • @Dravere:
    Moderne Systeme committen zwar beim malloc/new noch keinen Speicher, sehrwohl aber wird Adressraum reserviert.
    Und wenn die max. 4GB auf "flach" adressierenden 32 Bit Systemen weggelutscht sind, dann is halt aus.

    Ich schreibe absichtlich "committen keinen Speicher". Ob Speicher reserviert wird oder nicht kann ich nicht sagen. Ich hoffe schon, wäre ein hübsches Roulettespiel wenn nicht 🙂


  • Mod

    hustbaer schrieb:

    @Dravere:
    Moderne Systeme committen zwar beim malloc/new noch keinen Speicher, sehrwohl aber wird Adressraum reserviert.
    Und wenn die max. 4GB auf "flach" adressierenden 32 Bit Systemen weggelutscht sind, dann is halt aus.

    Ich schreibe absichtlich "committen keinen Speicher". Ob Speicher reserviert wird oder nicht kann ich nicht sagen. Ich hoffe schon, wäre ein hübsches Roulettespiel wenn nicht 🙂

    Was heißt das denn nun? In Bezug auf die Ausführung eines Programmes.



  • camper schrieb:

    Was heißt das denn nun? In Bezug auf die Ausführung eines Programmes.

    Dass du bei

    char* p = new char[n];
    *p=1;

    eine Access Violation bekommen kannst.

    Mein Code lief bei mir unter Vista und Ubuntu komplett durch und hat die Kiste gefreezt bis ich es gekillt hatte. Aber das ist natuerlich alles implementierungsabhaengig.



  • Siehe auch man: malloc unter "Bugs"



  • Shade Of Mine schrieb:

    Dass du bei

    char* p = new char[n];
    *p=1;

    eine Access Violation bekommen kannst.

    Kann man? Das wäre ja ziemlich grausig, da man dann ja nie sicherstellen kann dass nach einem scheinbar erfolgreichen new die Zugriffe auf den Zeiger auch problemlos ablaufen...



  • pumuckl schrieb:

    Kann man? Das wäre ja ziemlich grausig, da man dann ja nie sicherstellen kann dass nach einem scheinbar erfolgreichen new die Zugriffe auf den Zeiger auch problemlos ablaufen...

    Das ist die Quintessenz der letzten 10 Postings hier im Thread...



  • Tim schrieb:

    Siehe auch man: malloc unter "Bugs"

    Danke für den Hinweis.

    Weiss vielleicht auch jemand wie das Windows XP/2003/Vista/2008 machen?


Log in to reply