============== Beispiellösung [TOC] ============== :import: session04/step05/array.hpp :import: session04/step05/test1.cpp ---- SHELL (path=session04/step05,hostname=theon) -------- g++ -Wall -o test1 test1.cpp valgrind ./test1 ---------------------------------------------------------- Der zweidimensionale Fall funktioniert auf Anhieb: :import: session04/step05/test2.cpp ---- SHELL (path=session04/step05,hostname=theon) -------- g++ -Wall -o test2 test2.cpp valgrind ./test2 ---------------------------------------------------------- Zu den Vor- und Nachteilen ========================== * Als Vorteil könnte es betrachtet werden, dass wie in Java die einzelnen Zeilen unterschiedlich lang sein dürfen. Folgendes wäre also zulässig: :import: session04/step05/test3.cpp ---- SHELL (path=session04/step05,hostname=theon) -------- g++ -Wall -o test3 test3.cpp valgrind ./test3 ---------------------------------------------------------- * Die Nachteile können darin gesehen werden, dass wie in Java der Speicher nicht mehr zusammenhängend ist und der Zugriff über zwei Indirektionen erfolgt. Knacknuss ========= Leider werden die Zeilen zuerst erzeugt, dann kopierkonstruiert und danach wird die originale Kopie weggeworfen, obwohl ein _move constructor_ angeboten wird. Warum? Das Problem ist, dass eine `std::initializer_list` ihre Inhalte nur als `const` zur Verfügung stellt -- das macht eine Übergabe per _move constructor_ unmöglich. Das liegt daran, dass solche Initialisierungslisten durch den Übersetzer häufig in einem Speicherbereich mit Schreibschutz angelegt werden, so dass sie mehrfach genutzt werden können. Bei einer zwei-dimensionalen Matrix werden jedoch zunächst die Zeilen-Arrays in temporären Objekten konstruiert, die durchaus verschoben werden könnten. Dies geht jedoch leider nicht, selbst wenn `std::move` hinzugefügt wird. Historisch liegt das daran, dass `std::initializer_list` in einer Zeit entwickelt worden ist, in der die _move_-Semantik noch nicht umgesetzt war und dieser Sonderfall keine Berücksichtigung fand. Zwar gab es später einen Korrekturvorschlag von David Kraus (__N4166__ und __P0065__), aber diese Vorschläge sind bislang nicht in den Standard übernommen worden. Es gibt nicht-triviale Workarounds, einer findet sich im Blog von Sumant Tambe, der das Problem mit einer __Hilfsklasse__ löst, die _lvalues_ von _rvalues_ unterscheiden kann und, wenn ohne Gefahr möglich, das `const`-Attribut wegkonvertiert. :links: N4166 -> https://isocpp.org/files/papers/N4166.pdf P0065 -> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0065r0.pdf Hilfsklasse -> http://cpptruths.blogspot.com/2013/09/21-ways-of-passing-parameters-plus-one.html :navigate: up -> doc:index back -> doc:session04/page09