std::vector Frage


  • Mod

    Ihr habt wohl nicht erfasst, dass es sich hier um ein Pseudo- Example innerhalb von Pseudocode handelt, dass lediglich meiner Demonstration von iota dient. Es ist doch ersichtlich, dass die nötige Änderung meinem Einsatz eines Arrays statt des vector s geschuldet ist, und nicht dem Einsatz von iota selbst. Ich habe doch nie behauptet, dass mein Code mehr als Pseudo-Code ist, dessen einzige bedeutungsvolle Zeile der iota -Aufruf ist. Und genauso fordere ich firefly auf, das Beispiel selbst auf die im Eingangspost gegebene Definition von Example zu übertragen. Soll ich hier jeden trivialen Quatsch vorkauen, damit copy&paste ausreicht?

    SeppJ schrieb:

    Es gibt Grenzen, Seppl. Grenzen.

    Das ist nicht mein Name.

    Soll ich Dich beim Klarnamen nennen, oder fändest Du das schon dreist? Was für eine Sorte von Forenmitglied nimmt einem ein harmloses Wortspiel mit deren moniker übel?



  • @Arcoth
    Sei mal nicht so eingeschnappt. Wortspiele mit dem Namen nimmt man schnell mal übel, speziell wenn man in einer Diskussion diametrale Positionen hat.


  • Mod

    hustbaer schrieb:

    @Arcoth
    Sei mal nicht so eingeschnappt. Wortspiele mit dem Namen nimmt man schnell mal übel, speziell wenn man in einer Diskussion diametrale Positionen hat.

    Man sollte aber sein Unbehagen auf eine Weise ausdrücken, die mich nicht entfremdet. Hab's doch nicht so gemeint. 😞



  • @ heartless
    Die einfachste Lösung wäre wohl einen std::vector<std::unique_ptr<Foo>> statt eines std::vector<Foo> zu verwenden. Damit kontrollierst du explizit wann ein Objekt erzeugt bzw. zerstört wird, der std::vector funkt dir in keiner Weise dazwischen.



  • Arcoth schrieb:

    Ihr habt wohl nicht erfasst, dass es sich hier um ein Pseudo- Example innerhalb von Pseudocode handelt, dass lediglich meiner Demonstration von iota dient. Es ist doch ersichtlich, dass die nötige Änderung meinem Einsatz eines Arrays statt des vector s geschuldet ist, und nicht dem Einsatz von iota selbst. Ich habe doch nie behauptet, dass mein Code mehr als Pseudo-Code ist, dessen einzige bedeutungsvolle Zeile der iota -Aufruf ist. Und genauso fordere ich firefly auf, das Beispiel selbst auf die im Eingangspost gegebene Definition von Example zu übertragen. Soll ich hier jeden trivialen Quatsch vorkauen, damit copy&paste ausreicht?

    Ich habe die Example class definiton aus dem eigangspost genommen und da ist keinerlei default argument gegeben für den parameter im konstruktor.
    Oder was meinst du sonst?


  • Mod

    firefly schrieb:

    Arcoth schrieb:

    Ihr habt wohl nicht erfasst, dass es sich hier um ein Pseudo- Example innerhalb von Pseudocode handelt, dass lediglich meiner Demonstration von iota dient. Es ist doch ersichtlich, dass die nötige Änderung meinem Einsatz eines Arrays statt des vector s geschuldet ist, und nicht dem Einsatz von iota selbst. Ich habe doch nie behauptet, dass mein Code mehr als Pseudo-Code ist, dessen einzige bedeutungsvolle Zeile der iota -Aufruf ist. Und genauso fordere ich firefly auf, das Beispiel selbst auf die im Eingangspost gegebene Definition von Example zu übertragen. Soll ich hier jeden trivialen Quatsch vorkauen, damit copy&paste ausreicht?

    Ich habe die Example class definiton aus dem eigangspost genommen und da ist keinerlei default argument gegeben für den parameter im konstruktor.
    Oder was meinst du sonst?

    Natürlich ist da keiner. Das soll auch so bleiben. In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötigt. Das ändert aber nichts an der Anwendbarkeit von iota . Und Du hättest das Problem auch sofort erkannt, wenn Du die Fehlermeldung gelesen hättest, womit sich deine Frage erübrigt hätte. Nichts für Ungut, aber ich hab einfach nichts für solche unüberlegten Kommentare übrig.



  • Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?


  • Mod

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

  • Mod

    Arcoth schrieb:

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

    😕
    Sprich: Nein, es würde nicht funktionieren? Ob du nun implizit ein Array mit 0 initialisierst oder einen Vector explizit mit 0, macht doch dein Beispiel nicht besser. In jedem Fall legst du unnötige, und ausdrücklich nicht gewünschte Defaultobjekte an, bevor du die korrekten Objekte erzeugst.

    Ich bin sehr verwirrt: Wer bist du und was hast du mit dem echten Arcoth gemacht?



  • SeppJ schrieb:

    Arcoth schrieb:

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

    😕
    Sprich: Nein, es würde nicht funktionieren? Ob du nun implizit ein Array mit 0 initialisierst oder einen Vector explizit mit 0, macht doch dein Beispiel nicht besser. In jedem Fall legst du unnötige, und ausdrücklich nicht gewünschte Defaultobjekte an, bevor du die korrekten Objekte erzeugst.

    Ich stimme prinzipiell zu, allerdings hat der OP klargemacht, dass er solche Objekte wegen ihres Destruktors vermeiden möchte - ein Destruktor wird hier aber so wie ich das sehe nirgends aufgerufen, wodurch Arcoth's Lösung technisch gesehen schon den Anforderungen genügen würde.

    SeppJ schrieb:

    Ich bin sehr verwirrt: Wer bist du und was hast du mit dem echten Arcoth gemacht?

    Was die Pubertät so mit den Menschen macht... *duckundweg*


  • Mod

    Jodocus schrieb:

    SeppJ schrieb:

    Arcoth schrieb:

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

    😕
    Sprich: Nein, es würde nicht funktionieren? Ob du nun implizit ein Array mit 0 initialisierst oder einen Vector explizit mit 0, macht doch dein Beispiel nicht besser. In jedem Fall legst du unnötige, und ausdrücklich nicht gewünschte Defaultobjekte an, bevor du die korrekten Objekte erzeugst.

    Ich stimme prinzipiell zu, allerdings hat der OP klargemacht, dass er solche Objekte wegen ihres Destruktors vermeiden möchte - ein Destruktor wird hier aber so wie ich das sehe nirgends aufgerufen, wodurch Arcoth's Lösung technisch gesehen schon den Anforderungen genügen würde.

    Wenn der Konstruktor tatsächlich Ressourcen belegt, was der Beschreibung zufolge anzunehmen ist, dann muss eine Zuweisung die überschriebene Ressource auch wieder freigeben (weshalb man in diesem Fall die Zuweisung normalerweise mit Copy&Swap implementiert). Dies ist fast mit Sicherheit der Fall, denn sonst wäre nicht betont worden, dass unnötige Konstruktor und Destruktoraufrufe vermieden werden sollten. Was einen nicht-trivialen Destruktor und damit auch eine nicht-triviale Zuweisung impliziert.

    Jodocus schrieb:

    SeppJ schrieb:

    Ich bin sehr verwirrt: Wer bist du und was hast du mit dem echten Arcoth gemacht?

    Was die Pubertät so mit den Menschen macht... *duckundweg*

    Ich bin ziemlich sicher, dass Arcoth Anfang bis Mitte 20 ist.



  • SeppJ schrieb:

    Jodocus schrieb:

    SeppJ schrieb:

    Arcoth schrieb:

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

    😕
    Sprich: Nein, es würde nicht funktionieren? Ob du nun implizit ein Array mit 0 initialisierst oder einen Vector explizit mit 0, macht doch dein Beispiel nicht besser. In jedem Fall legst du unnötige, und ausdrücklich nicht gewünschte Defaultobjekte an, bevor du die korrekten Objekte erzeugst.

    Ich stimme prinzipiell zu, allerdings hat der OP klargemacht, dass er solche Objekte wegen ihres Destruktors vermeiden möchte - ein Destruktor wird hier aber so wie ich das sehe nirgends aufgerufen, wodurch Arcoth's Lösung technisch gesehen schon den Anforderungen genügen würde.

    Wenn der Konstruktor tatsächlich Ressourcen belegt, was der Beschreibung zufolge anzunehmen ist, dann muss eine Zuweisung die überschriebene Ressource auch wieder freigeben (weshalb man in diesem Fall die Zuweisung normalerweise mit Copy&Swap implementiert). Dies ist fast mit Sicherheit der Fall, denn sonst wäre nicht betont worden, dass unnötige Konstruktor und Destruktoraufrufe vermieden werden sollten. Was einen nicht-trivialen Destruktor und damit auch eine nicht-triviale Zuweisung impliziert.

    Klar, so wird es wahrscheinlich auch sein. Aber es ist trotzdem erst mal nur Spekulation, bis der Threaderöffner Klarheit schafft.

    SeppJ schrieb:

    Jodocus schrieb:

    SeppJ schrieb:

    Ich bin sehr verwirrt: Wer bist du und was hast du mit dem echten Arcoth gemacht?

    Was die Pubertät so mit den Menschen macht... *duckundweg*

    Ich bin ziemlich sicher, dass Arcoth Anfang bis Mitte 20 ist.

    Okay, das war etwas fies. Ich denke, das ist einfach nur ein Fall von "wenn man einen Hammer hat, sieht die Welt aus wie ein Nagel". std::iota sah zu verlockend nach dem aus, was der TE vermutlich gebrauchen könnte.



  • SeppJ schrieb:

    Arcoth schrieb:

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

    😕
    Sprich: Nein, es würde nicht funktionieren? Ob du nun implizit ein Array mit 0 initialisierst oder einen Vector explizit mit 0, macht doch dein Beispiel nicht besser. In jedem Fall legst du unnötige, und ausdrücklich nicht gewünschte Defaultobjekte an, bevor du die korrekten Objekte erzeugst.

    Zusätzlich zu den default objekten werden in jedem iota call ein temporary object erstellt:
    https://ideone.com/W7lAzJ
    Was noch weniger gewünscht ist vom OP


  • Mod

    Seppl schrieb:

    Arcoth schrieb:

    manni66 schrieb:

    Arcoth schrieb:

    In meiner Demonstration habe ich einfach flüchtig ein Array statt einem vector genommen, was einen Default-Konstruktor benötig.

    Und mit einem vector würde es ohne Defaultkonstruktor funktionieren?

    😕

    std::vector<Example> vec(0, 10);
    std::iota(std::begin(e), std::end(e), 0);
    

    😕
    Sprich: Nein, es würde nicht funktionieren? Ob du nun implizit ein Array mit 0 initialisierst oder einen Vector explizit mit 0, macht doch dein Beispiel nicht besser. In jedem Fall legst du unnötige, und ausdrücklich nicht gewünschte Defaultobjekte an, bevor du die korrekten Objekte erzeugst.

    Natürlich ist der Code furchtbar suboptimal. Was sowohl daran liegt, dass die Klasse ein RAII-konformes Interface hat, als auch dass iota_n in der STL fehlt. Dann machen wir es eben richtig:

    std::vector<Example> e;
    boost::algorithm::iota_n(back_inserter(e), 10, 0);
    
    // Oder (nicht ganz ernst gemeint)
    std::vector<Example> e;
    std::generate_n(back_inserter(e), 10,  [i = 0] () mutable {return Example(i++);});
    
    // Oder
    auto r = boost::irange(0, 9);
    std::vector<Example> e(r.begin(), r.end());
    

    Und in Bezug auf

    hustbaer schrieb:

    Die einfachste Lösung wäre wohl einen std::vector<std::unique_ptr<Foo>> statt eines std::vector<Foo> zu verwenden. Damit kontrollierst du explizit wann ein Objekt erzeugt bzw. zerstört wird, der std::vector funkt dir in keiner Weise dazwischen.

    // Oder
    std::vector<std::optional<Example>> e(10);
    std::iota(begin(e), end(e), 0);
    

    Der Punkt ist: man kann hier definitiv einen Nagel reinhauen, man muss nur hart genug schlagen! Auch wenn ich konzediere, dass mein ursprüngliches Beispiel nicht-trivial verändert werden muss, um es Sinn ergeben zu lassen. Dafür muss ich mich entschuldigen, ich habe das nicht mal ansatzweise durchdacht.

    @firefly: Diese Temporaries werden alle gemoved, vorausgesetzt der TE hat die Move-Semantik seiner Klasse richtig implementiert. Somit dürfte jeder entsprechende Destruktoraufruf ein no-op sein, da die Temporary keine Ressource mehr besitzt. Aber wie bereits erwähnt, das ist nur Spekulation.



  • Arcoth schrieb:

    Was sowohl daran liegt, dass die Klasse ein RAII-konformes Interface hat, als auch dass iota_n in der STL fehlt. Dann machen wir es eben richtig:

    std::vector<Example> e;
    boost::algorithm::iota_n(back_inserter(e), 10, 0);
    

    Wenn die klasse kein saubere implementierung von copy und/oder move semantic hat wäre hier noch ein

    e.reserve(10)
    

    von Vorteil um beim automatischen resize des vectors ein copy/move zu vermeiden.
    Falls boost nicht verwendet werden kann/soll kann man das gleiche auch mit folgende code erreichen:

    std::vector<Example> e;
    e.reserve(10);
    for (int i = 0; i < 10; ++i)
    {
      e.emplace_back(i);
    }
    

    Wobei der code c++11 features benötigt.


  • Mod

    firefly schrieb:

    Arcoth schrieb:

    Was sowohl daran liegt, dass die Klasse ein RAII-konformes Interface hat, als auch dass iota_n in der STL fehlt. Dann machen wir es eben richtig:

    std::vector<Example> e;
    boost::algorithm::iota_n(back_inserter(e), 10, 0);
    

    Wenn die klasse kein saubere implementierung von copy und/oder move semantic hat wäre hier noch ein

    e.reserve(10)
    

    von Vorteil um beim automatischen resize des vectors ein copy/move zu vermeiden.

    Wenn die Klasse keine saubere Move-Semantik hat, es aber bedeutend ist, ihre Ressourcen nicht zu duplizieren, hat der TE etwas anderes aufzuholen. Ersteres ist doch gerade aus dem ubiquitaeren Wunsch geboren worden, Ressourcen nicht verschwenderisch kopieren zu muessen, wenn man die besitzenden Objekte verschieben muss. Ich meine, sogar in C++03 koennte man die Boost.Move Loesung einsetzen.



  • Ich habe da noch ein Problem. Im Moment sieht es so bei mir aus:

    std::vector<Example> examples;
      controllers.reserve(100);
      for(int i = 0; i < 100; i++)
      {
        examples.emplace_back(std::move(Example(i)));
    
        examples[i].foo();
    
      }
    

    Es wird dennoch für jedes Example ein Destruktor aufgerufen, bevor das Ende der Gültigkeit des vectors erreicht wird.
    Anschließend gibt es noch einen zweiten Destruktor. Ich gehe also davon aus, dass irgendwo kopiert wird, was ich vermeiden möchte.

    Ich lasse mir auch gerne erklären, was da genau passiert, wenn sich jemand die Zeit dafür nehmen möchte.


  • Mod

    emplace_back(i)?

    Auch wenn du den temporären Wert movest, so existiert er doch als Objekt und muss irgendwann zerstört werden. Wenn du die move-Semantik korrekt implementiert hast, dann sollte dabei aber keine Ressourcenfreigabe nötig sein, schließlich wurden die Ressourcen woanders hin gemoved und nicht kopiert. Anscheinend ist das aber nicht der Fall, sonst würdest du nicht fragen. Oder fragst du, weil du nur die Anzahl der Destruktoraufrufe gezählt hast, ohne der Spur der Ressourcen zu folgen?

    Mit emplace_back(i) sollte sich das aber auf jeden Fall erledigen, egal ob du berechtigt oder unberechtigt fragst. Dazu ist emplace schließlich da. emplace und move gleichzeitig sind hingegen eine komische Kombination.



  • (removed, habe dasselbe wie SeppJ geschrieben)



  • Ok, habe emplace_back falsch angewandt und stumpf Destruktor-Aufrufe gezählt.


Anmelden zum Antworten