============== Beispiellösung [TOC] ============== :import: session04/step04/array.hpp :import: session04/step04/test1.cpp [fold] ---- SHELL (path=session04/step04,hostname=theon) -------- g++ -Wall -o test1 test1.cpp valgrind ./test1 ---------------------------------------------------------- Zur Frage zu `test2.cpp`: :import: session04/step04/test2.cpp [fold] ---- SHELL (path=session04/step04,hostname=theon) -------- g++ -Wall -o test2 test2.cpp echo 1 2 3 | valgrind ./test2 ---------------------------------------------------------- Das Problem ist hier, dass es sich bei `std::istream_iterator` um einen Input-Iterator handelt und nicht um einen Forward-Iteratoren, d.h. ein Inkrement verkonsumiert und ein Weg zurück ist nicht möglich. Werfen wir einen Blick auf den zum Einsatz kommenden Konstruktor: ---- CODE (type=cpp) ---------------------------------------------------------- template Array(Iterator it1, Iterator it2) : Array(AllocateStorage, std::distance(it1, it2)) { std::size_t index = 0; while (it1 != it2 && index < size) { new (data + index++) T(*it1++); } size = index; // just in case } ------------------------------------------------------------------------------- Bevor wir hier zum Kopierkonstruieren kommen, wird `std::distance` aufgerufen, das auf die triviale Methode mit linearem Aufwand zurückkommen muss, die etwa wie folgt aussieht: ---- CODE (type=cpp) ---------------------------------------------------------- template std::ptrdiff_t distance(Iterator it1, Iterator it2) { std::ptrdiff_t count = 0; while (it1 != it2) { ++count; ++it1; } return count; } ------------------------------------------------------------------------------- Nachdem `std::distance` aufgerufen worden ist, haben wir die zwei Iteratoren _it1_ und _it2_, die nicht gleich sind, wodurch wir beim ersten Mal in die Schleife eintreten. Bei `std::istream_iterator` wird nicht beim Dereferenzieren gelesen. Stattdessen wird das erste Element beim Konstruieren eingelesen, die späteren folgen beim Inkrementieren. Wenn beim Inkrementieren das Eingabe-Ende erkannt wird, entsteht daraus der Ende-Iterator. Somit wird der erste eingelesene Wert, der bei `it1` gespeichert ist, noch übertragen. Das Inkrement stellt das Eingabe-Ende erneut fest und liefert den Ende-Iterator, so dass die Schleife nach der ersten Iteration endet. Somit haben wir den lästigen Fall, dass wir weniger Elemente bekommen haben als ursprünglich geplant. Was tun? Der einfachste Weg besteht darin, die Größe _size_ anzupassen mit der unangenehmen Konsequenz, dass ein Teil des Speichers verschwendet wird. (Das ließe sich zwar mit Hilfe von `std::realloc` lösen, aber der Aufwand lohnt sich nicht, da es nicht sinnvoll ist, ein festzudimensionierendes Array mit Input-Iteratoren zu initialisieren, die nicht die Fähigkeiten eines Forward-Iterators haben. Die nächsten vier Tests klappen auch wie erwartet: :import: session04/step04/test3.cpp [fold] :import: session04/step04/test4.cpp [fold] :import: session04/step04/test5.cpp [fold] :import: session04/step04/test6.cpp [fold] ---- SHELL (path=session04/step04,hostname=theon) -------- g++ -Wall -o test3 test3.cpp echo 1 2 3 | valgrind ./test3 g++ -Wall -o test4 test4.cpp valgrind ./test4 g++ -Wall -o test5 test5.cpp valgrind ./test5 g++ -Wall -o test6 test6.cpp valgrind ./test6 ---------------------------------------------------------- Der letzte Test initialisiert nicht das Array, weil es sich bei _value_ um eine lokale Kopie handelt, wenn wir diese verändern, hat dies keinen Effekt: :import: session04/step04/test7.cpp [fold] ---- SHELL (path=session04/step04,hostname=theon) -------- g++ -Wall -o test7 test7.cpp ./test7 ---------------------------------------------------------- Das Problem lässt sich lösen, wenn wir mit einer Referenz arbeiten: :import: session04/step04/test8.cpp ---- SHELL (path=session04/step04,hostname=theon) -------- g++ -Wall -o test8 test8.cpp ./test8 ---------------------------------------------------------- Oder explizit mit Iteratoren: :import: session04/step04/test9.cpp ---- SHELL (path=session04/step04,hostname=theon) -------- g++ -Wall -o test9 test9.cpp ./test8 ---------------------------------------------------------- :navigate: up -> doc:index back -> doc:session04/page07 next -> doc:session04/page09