Size: 32220
Comment:
|
Size: 32035
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 2: | Line 2: |
Also ich habe die _capacity variable im Dekonstructor benutzt und damit brauche ich auch nicht die ganze Geschichte von der Verdopplung von _capacity. Gruß '''Dario 27Mai10 21:51''' |
Fragen und Kommentare zur 5. Vorlesung / zum 5. Übungsblatt
@Robin: das kommt drauf an, wie du deine Liste initialisierst. Ich initialisiere z.B. mit NULL somit ist meine _capacity am anfang 0. Im push_back wird die Variable dann beim ersten Element auf 1 gesetzt und bei weiteren Elementen bei größerem Platzbedarf immer verdoppelt (if/else). Die Variable braucht man tatsächlich "nur" im Konstruktor und im push_back(). _capacity muss man erhöhen, wenn die Kapazität voll ist, also _size genau so groß ist wie _capacity und dann ein neues Element hinzu kommen soll. Hoffe, dass konnte helfen Gruß Ben 27.Mai10 21:43
Eine Frage zur der Membervariable _capacity und zwar steht in der Aufgabenstellung : Initialisieren Sie diese Variable im Konstruktor geeignet. Aber was soll dieses "geeignet"? Im Konstruktor hat man die size der Liste noch nicht, deshalb kann man der Variable _capacity diesen Wert nicht zu weisen. Sollen wir nun einen Wert willkürlich wählen z.B: 50, oder wie ist das zu verstehen? Braucht man für die Funktion int pop_back() auch diese Variable _capacity. Sorry aber das mit dieser Variable verursacht bei mir für Schwierigkeiten. So wie ich es jetzt verstanden habe, braucht man die Variable nur in der push_back(int x), und zwar soll dann die _capacity erhöht werden, wenn man die _size überschreitet. Was auch logisch erscheint, denn wenn man ein Integer hinzufügen will, aber die Liste bereits voll ist, so muss man neuen Speicher anfragen, die alte Liste kopieren und dann den Wert von push_back hinzufügen. Danach soll man den alten Speicher, den man nicht mehr brauch wieder freigeben, richtig? Hoffe mir kann jemand helfen. Gruß Robin 27 Main 21:22
Etwas Allgemeineres: Kann es sein, dass Hudson ein Problem mit unseren Ferien hat (es klagt jedenfalls, wenn man die 0 stehen lässt, weil es keinen Ordner uebungsblatt-6 gibt...)? SebastianS 27Mai10 02:33
@Dario Immer wenn du ein neues Element beim "parsen" oder beim "pushen" in die Liste schreibst, erhöhst du _size um 1. Ben 26Mai10
Die push- und pop_back Funktionen werden auf ein Objekt vom Typ ListOfIntegers aufgerufen (da ist also logischerweise ein Array mit Integern drin, nämlich _elements). Die _size (und manchmal auch die _capacity) musst du beim Aufruf der Funktionen entsprechend anpassen. SebastianD 26Mai10 22:04
Danke aber was ich nicht wirklich verstehe ist, wie man die Size von der Liste "messen" kann. Bei Parselistofintegers habe ich einfach die Anzahl von komma gezählt, aber hier geht´s nicht. Soll ich davon ausgehen ,dass die List in der Push oder pop function schon geparsed sind oder können auch String sein? Dario 26Mai10 21:50
@Dario Du solltest am Ende 3 Klassenvariablen haben: 1. _elements, diese enthält die Liste, 2. _size, diese enthält die Anzahl der Elemente und 3. _capacity, diese enthält die Größe deines allokierten Speichers.
_elements = new int[20]; _elements[0] = 7; _elements[1] = 8; _elements[2] = 2; // nun müssen die anderen Variablen folgende Werte haben: _size = 3; _capacity = 20;
Gruß Ben 26Mai10 21:47
Ich habe so gemacht , weil ich nicht ganau weiß , wie man die Größe von meinem _element in Push oder pop_backfunktion bestimmen kann. Dario 26Mai10 20:16
@Dario: Das verstehe ich nicht, warum wollen Sie der push_back oder pop_back Funktion ein Listenobjekt als Argument mitgeben? Die Methoden werden doch immer gerade von einem Listenobjekt aufgerufen, so wie z.B. in ListOfIntegers list; gefolgt von list.push_back(5). Die _capacity Variable brauchen Sie deswegen, weil es einmal die aktuelle Anzahl von Elementen in der Liste gibt (size) und einmal, für wieviel Elemente Platz alloziert wurde (_capacity). Das macht man deswegen, damit man nicht nach jedem push_back neu Platz allozieren und umkopieren muss, sondern nur ab und zu. Genauer gesagt kriegt man so eine durchschnittliche (amortisierte) Laufzeit für push_back, die unabhängig von der Listenlänge ist. Hannah 26Mai10 20:21
@Betim: Ja, wie Dario sagt, Ihr getElement ist ja eine ganz normale Funktion / Methode, und die ruft man mit runden Klammern auf, nicht mit eckigen. Hannah 26Mai10 20:16
@David: Ja, wie in der Vorlesung vorgemacht, soll man die -1 weglassen. Braucht man ja auch nicht mehr wenn man die _size hat. Hannah 26Mai10 20:15
Bei der 2te Aufgabe darf man die push_back und pop_back mit einem zusätzlichem Argument implementieren? damit brauche ich nicht mehr die _capacity variable. Wie folgendes:
// die list 1 ist schon geparsed. ListOfIntegers push; push.push_back( &list1 , x)
Dasselbe auch für pop_back. Grüße Dario 26Mai10 20:00
@Betim.Probier es einfach anstatt[] mit () klammer also getElement(1) anstatt getElement [0] Dario 26Mai10 17:52
@David: Ich hab das mit -1 entfernt und benutze stattdessen _size. Ich glaube auch, man soll das so machen. Aber mal ne andere Frage: Nachdem das mit FRIEND_TEST nicht funktioniert hat, habe ich mir eine getElement(int n) Methode geschrieben, die eben das n-te Element zurückgibt. Die sieht so aus:
int ListOfIntegers::getElement(int n) { assert(n >= 0); return _elements[n]; }
Der Test schaut so aus:
TEST(ListOfIntegers, parseFromString) { ListOfIntegers list1; const char* listAsString = " 1 , 5, 78 "; list1.parseFromString(listAsString); ASSERT_EQ(1, list1.getElement[0]); ASSERT_EQ(5, list1.getElement[1]); ASSERT_EQ(78, list1.getElement[2]);
Und folgender Fehler taucht beim Kompilieren auf:
ListOfIntegersTest.cpp: In member function ‘virtual void ListOfIntegers_parseFromString_Test::TestBody()’: ListOfIntegersTest.cpp:14: error: invalid types ‘<unresolved overloaded function type>[int]’ for array subscript
Hat jemand eine Ahnung was das zu bedeuten hat?? Betim 26Mai 17:35
Mir ist da auch noch eine Frage eingefallen: Kann ich wie im Blatt zuvor das Listenende mit -1 definieren, oder muss alles nur noch mit _size erfolgen? David Z. 26Mai10 16:17
@Alle: Das mit dem & bei den Funktionsargumenten werde ich in der nächsten Vorlesung erklären. Schreiben Sie es für dieses Übungsblatt einfach hin. Hannah 26Mai10 01:02
@Betim: Kopieren können Sie doch mit einer ganz normalen for Schleife, hier ist ein Beispiel:
int* newElements = new int[newSize]; assert(size <= newSize); for (int i = 0; i < size; ++i) newElements[i] = _elements[i]; delete[] _elements; _elements = newElements;
Wie in der Vorlesung erklärt (schauen Sie sie sich vielleicht nochmal an, auch die mit den Zeigern), sind newElements und _elements in meinem Codeschnipsel oben einfach Zeiger auf Speicherplatz, wobei nach der ersten Zeile _elements auf den alten (vorher einmal allozierten) Speicherplatz zeigt, und newElements auf den gerade neu allozierten. Nach der for Schleife stehen die Elemente der Liste an beiden Stellen. Mit dem delete[] _elements wird dann der alte Speicherplatz freigegeben. Mit dem _elements = newElements zeigt jetzt der _elements Zeiger auf den neuen Speicherplatz. Hannah 26Mai10 00:59
@Daniel & Veit: Ja, genau, das ist der Fehler, den ich in der Vorlesung gerne zeigen wollte, aber es gelang mir nicht. Er kann auftreten (muss aber nicht), wenn man delete[] auf einen Zeiger anwendet, der auf Speicher zeigt, der bereits frei gegeben worden ist, oder wenn man über den allozierten Bereich hinausgeschrieben hat. Deswegen muss man höllisch aufpassen mit new und delete. Hannah 26Mai10 00:51
@Ben: Tun Sie bei Aufgabe 1 so, als wüssten Sie noch nichts von Aufgabe 2. Und nachdem Sie Aufgabe 2 gemacht haben, brauchen Sie an Aufgabe 1 nichts mehr zu ändern. Insbesondere können Sie in den Methoden parseFromString und getInterleaveOf die Membervariable _capacity ignorieren. Wobei es natürlich sauberer wäre, Sie da zu setzen, was ja auch einfach ist, Sie können Sie einfach auf denselben Wert wie _size setzen. Hannah 26Mai10 00:48
@Dario: Ein Objekt list der Klasse ListOfInteger ist ja kein Feld, also können Sie nicht einfach list[i] schreiben. Sie müssen list._elements[i] schreiben. Hannah 26Mai10 00:40
Frage zur Aufgabe2: Wie kann man die alte Liste in die neue Liste kopieren? Angenommen aktuelle Liste ist zu groß, ich hol mir mehr Speicher mittels _elements = new int[2*..]. So und wie kopiere ich jetzt die alten Werte hier rein? Und wenn ich danach delete[] _elements mache, um den alten Speicherplatz freizugeben, dann ist doch der jetzige auch weg oder?? Mfg BetimM 26Mai o_O:35
Komisch, ich sollte eigentlich eine Mail bekommen, wann immer hier jemand etwas postet, habe aber den ganzen Dienstag keine Benachrichtigungsmail bekommen. Ich werde mir die Fragen am Mittwoch anschauen, sorry für die Verspätung. Hannah 26Mai10 00:34
interleaveListsOfIntegers(const ListOfIntegers& list1, const ListOfIntegers& list2)
Ah ja, diese & ist dann wohl für die Referenz zuständing. Jetzt gehts, Danke Daniel 25Mai10 22:47
Der Fehler kommt, wenn man delete[] auf schon gelöschte Listen anwendet. Ein Workaround ist es, die Liste nach dem Löschen den Wert 0 zu geben. Dein Fehler kann aber auch auftreten, wenn du bei interleave keine Referenz sondern eine Kopie des Objektes übergibst. Ben 15Mai10 22:39
@Veit dieses Problem habe ich auch, bei mir sind die Probleme schon mit dem Aufruf der Main und Eingabewerte über 3-4 Zahlen pro Liste erzeugbar (Fehler liegt wohl im interleave):
./ListProcessingMain "1,4,1,2" "4,3,2" first list is: 1,4,1,2 second list is: 4,3,2 interleved list is: 1,4,4,3,1,2,2 *** glibc detected *** ./ListProcessingMain: double free or corruption (fasttop): 0x0000000000d35030 *** ======= Backtrace: ========= /lib/libc.so.6(+0x775b6)[0x7f2fc399a5b6] /lib/libc.so.6(cfree+0x73)[0x7f2fc39a0e53] ./ListProcessingMain[0x400b55] ./ListProcessingMain[0x400a55] /lib/libc.so.6(__libc_start_main+0xfd)[0x7f2fc3941c4d] ./ListProcessingMain[0x400819] ======= Memory map: ======== 00400000-00402000 r-xp 00000000 08:05 35577934 /home/daniel/c++/uebungsblatt-5/ListProcessingMain 00601000-00602000 r--p 00001000 08:05 35577934 /home/daniel/c++/uebungsblatt-5/ListProcessingMain 00602000-00603000 rw-p 00002000 08:05 35577934 /home/daniel/c++/uebungsblatt-5/ListProcessingMain 00d35000-00d56000 rw-p 00000000 00:00 0 [heap] 7f2fbc000000-7f2fbc021000 rw-p 00000000 00:00 0 7f2fbc021000-7f2fc0000000 ---p 00000000 00:00 0 7f2fc3923000-7f2fc3a9b000 r-xp 00000000 08:05 33555453 /lib/libc-2.11.1.so 7f2fc3a9b000-7f2fc3c9b000 ---p 00178000 08:05 33555453 /lib/libc-2.11.1.so 7f2fc3c9b000-7f2fc3c9f000 r--p 00178000 08:05 33555453 /lib/libc-2.11.1.so 7f2fc3c9f000-7f2fc3ca0000 rw-p 0017c000 08:05 33555453 /lib/libc-2.11.1.so 7f2fc3ca0000-7f2fc3ca5000 rw-p 00000000 00:00 0 7f2fc3ca5000-7f2fc3cbb000 r-xp 00000000 08:05 33555487 /lib/libgcc_s.so.1 7f2fc3cbb000-7f2fc3eba000 ---p 00016000 08:05 33555487 /lib/libgcc_s.so.1 7f2fc3eba000-7f2fc3ebb000 r--p 00015000 08:05 33555487 /lib/libgcc_s.so.1 7f2fc3ebb000-7f2fc3ebc000 rw-p 00016000 08:05 33555487 /lib/libgcc_s.so.1 7f2fc3ebc000-7f2fc3f3e000 r-xp 00000000 08:05 33555503 /lib/libm-2.11.1.so 7f2fc3f3e000-7f2fc413d000 ---p 00082000 08:05 33555503 /lib/libm-2.11.1.so 7f2fc413d000-7f2fc413e000 r--p 00081000 08:05 33555503 /lib/libm-2.11.1.so 7f2fc413e000-7f2fc413f000 rw-p 00082000 08:05 33555503 /lib/libm-2.11.1.so 7f2fc413f000-7f2fc4235000 r-xp 00000000 08:05 100776696 /usr/lib/libstdc++.so.6.0.13 7f2fc4235000-7f2fc4435000 ---p 000f6000 08:05 100776696 /usr/lib/libstdc++.so.6.0.13 7f2fc4435000-7f2fc443c000 r--p 000f6000 08:05 100776696 /usr/lib/libstdc++.so.6.0.13 7f2fc443c000-7f2fc443e000 rw-p 000fd000 08:05 100776696 /usr/lib/libstdc++.so.6.0.13 7f2fc443e000-7f2fc4453000 rw-p 00000000 00:00 0 7f2fc4453000-7f2fc4473000 r-xp 00000000 08:05 33555429 /lib/ld-2.11.1.so 7f2fc4653000-7f2fc4657000 rw-p 00000000 00:00 0 7f2fc466f000-7f2fc4672000 rw-p 00000000 00:00 0 7f2fc4672000-7f2fc4673000 r--p 0001f000 08:05 33555429 /lib/ld-2.11.1.so 7f2fc4673000-7f2fc4674000 rw-p 00020000 08:05 33555429 /lib/ld-2.11.1.so 7f2fc4674000-7f2fc4675000 rw-p 00000000 00:00 0 7fffffa65000-7fffffa7a000 rw-p 00000000 00:00 0 [stack] 7fffffb2b000-7fffffb2c000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted
Kann mir jemand sagen, was mir dieser Fehler sagen möchte? Daniel 25Mai10 22:29
[ RUN ] ListOfIntegers.getInterleaveOf *** glibc detected *** ./ListProcessingTest: free(): invalid next size (fast): 0x0000000001b38570 *** ======= Backtrace: ========= /lib/libc.so.6[0x2abd146e6dd6] /lib/libc.so.6(cfree+0x6c)[0x2abd146eb74c] ./ListProcessingTest[0x403675] ./ListProcessingTest[0x402747] /usr/local/lib/libgtest.so.0(_ZN7testing4Test3RunEv+0xaa)[0x2abd14a060ea] /usr/local/lib/libgtest.so.0(_ZN7testing8internal12TestInfoImpl3RunEv+0x108)[0x2abd14a061f8] /usr/local/lib/libgtest.so.0(_ZN7testing8TestCase3RunEv+0xbd)[0x2abd14a062bd] /usr/local/lib/libgtest.so.0(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+0x231)[0x2abd14a06541] /usr/local/lib/libgtest_main.so.0(main+0x3e)[0x2abd13cc3a7e] /lib/libc.so.6(__libc_start_main+0xfd)[0x2abd1468fabd] ./ListProcessingTest[0x4015a9] ======= Memory map: ======== 00400000-00406000 r-xp 00000000 00:14 537312 /home/veit/persoenlich/studium/ss10/cpp/repository/uebungsblatt-5/ListProcessingTest 00605000-00606000 r--p 00005000 00:14 537312 /home/veit/persoenlich/studium/ss10/cpp/repository/uebungsblatt-5/ListProcessingTest 00606000-00607000 rw-p 00006000 00:14 537312 /home/veit/persoenlich/studium/ss10/cpp/repository/uebungsblatt-5/ListProcessingTest 01b38000-01b59000 rw-p 00000000 00:00 0 [heap] 2abd13aa3000-2abd13ac2000 r-xp 00000000 fc:01 2624 /lib/ld-2.10.1.so 2abd13ac2000-2abd13ac6000 rw-p 00000000 00:00 0 2abd13cc1000-2abd13cc2000 r--p 0001e000 fc:01 2624 /lib/ld-2.10.1.so 2abd13cc2000-2abd13cc3000 rw-p 0001f000 fc:01 2624 /lib/ld-2.10.1.so 2abd13cc3000-2abd13cc4000 r-xp 00000000 fc:01 24035 /usr/local/lib/libgtest_main.so.0.0.0 2abd13cc4000-2abd13ec3000 ---p 00001000 fc:01 24035 /usr/local/lib/libgtest_main.so.0.0.0 2abd13ec3000-2abd13ec4000 r--p 00000000 fc:01 24035 /usr/local/lib/libgtest_main.so.0.0.0 2abd13ec4000-2abd13ec5000 rw-p 00001000 fc:01 24035 /usr/local/lib/libgtest_main.so.0.0.0 2abd13ec5000-2abd13fb7000 r-xp 00000000 fc:01 178424 /usr/lib/libstdc++.so.6.0.13 2abd13fb7000-2abd141b7000 ---p 000f2000 fc:01 178424 /usr/lib/libstdc++.so.6.0.13 2abd141b7000-2abd141be000 r--p 000f2000 fc:01 178424 /usr/lib/libstdc++.so.6.0.13 2abd141be000-2abd141c0000 rw-p 000f9000 fc:01 178424 /usr/lib/libstdc++.so.6.0.13 2abd141c0000-2abd141d5000 rw-p 00000000 00:00 0 2abd141d5000-2abd14257000 r-xp 00000000 fc:01 2631 /lib/libm-2.10.1.so 2abd14257000-2abd14457000 ---p 00082000 fc:01 2631 /lib/libm-2.10.1.so 2abd14457000-2abd14458000 r--p 00082000 fc:01 2631 /lib/libm-2.10.1.so 2abd14458000-2abd14459000 rw-p 00083000 fc:01 2631 /lib/libm-2.10.1.so 2abd14459000-2abd1445a000 rw-p 00000000 00:00 0 2abd1445a000-2abd14470000 r-xp 00000000 fc:01 238 /lib/libgcc_s.so.1 2abd14470000-2abd1466f000 ---p 00016000 fc:01 238 /lib/libgcc_s.so.1 2abd1466f000-2abd14670000 r--p 00015000 fc:01 238 /lib/libgcc_s.so.1 2abd14670000-2abd14671000 rw-p 00016000 fc:01 238 /lib/libgcc_s.so.1 2abd14671000-2abd147d7000 r-xp 00000000 fc:01 2627 /lib/libc-2.10.1.so 2abd147d7000-2abd149d6000 ---p 00166000 fc:01 2627 /lib/libc-2.10.1.so 2abd149d6000-2abd149da000 r--p 00165000 fc:01 2627 /lib/libc-2.10.1.so 2abd149da000-2abd149db000 rw-p 00169000 fc:01 2627 /lib/libc-2.10.1.so 2abd149db000-2abd149e0000 rw-p 00000000 00:00 0 2abd149e0000-2abd14a1b000 r-xp 00000000 fc:01 24033 /usr/local/lib/libgtest.so.0.0.0 2abd14a1b000-2abd14c1b000 ---p 0003b000 fc:01 24033 /usr/local/lib/libgtest.so.0.0.0 2abd14c1b000-2abd14c1c000 r--p 0003b000 fc:01 24033 /usr/local/lib/libgtest.so.0.0.0 2abd14c1c000-2abd14c1d000 rw-p 0003c000 fc:01 24033 /usr/local/lib/libgtest.so.0.0.0 2abd14c1d000-2abd14c1f000 rw-p 00000000 00:00 0 2abd18000000-2abd18021000 rw-p 00000000 00:00 0 2abd18021000-2abd1c000000 ---p 00000000 00:00 0 7fff40ab1000-7fff40ac6000 rw-p 00000000 00:00 0 [stack] 7fff40bef000-7fff40bf0000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted make: *** [test] Error 134
Werde aus dieser Fehlerausgabe von GTest nicht schlau. Das Programm funktioniert gut, wenn ich es einfach so teste, also per Main-Funktion. Die Testfälle könnten natuerlich den Fehler beherbergen, aber ich wusste nicht ob man die hier posten darf oder nicht. Wo muss ich suchen? Veit 25Mai10 22:16
Hallo, ich habe mehrere Fragen zum Blatt:
- Soll die Aufgabe 1 mit den Methoden aus Aufgabe 2 gelöst werden (spätestens wenn man Aufgabe 2 implementiert)?
- Soll in Aufgabe 1 (wenn nicht die push/pop Methoden genutzt werden) auch _capacity angepasst werden?
- Soll, falls Punkt 2 eintritt, auch die Regel mit dem verdoppeln der Kapazität greifen?
- Beist sich das nicht, wenn man push_back mit pop_back testet und umgekehrt? Weil scheint mir irgendwie "komisch", dass der pop_back Test vom (ungetesteten) push_back abhängt und umgekehrt. Wenn theoretisch was schief läuft, weiß ich ja nicht woran es lag. (Ok hier sind die Methoden "einfach", aber bei komplexeren Dingen könnte das doch ein problem geben)
Ben 25Mai10 20:39
@Florin: danke für die Antwort, ich habe mich ein bisschen über Referenzen dokumentiert und habe gelesen ,dass es also fast wie eine zweite name(oder copie) für die Variable ist. Ich bin davon ausgegangen ,dass einen Code wie folgendes stimmt. Wenn ich meine interleavefunktion ausrufe.
void ListOfIntegers::interLeaveListOfIntegers(const ListOfIntegers& list1, const ListOfIntegers& list2) while ((ck1 == false) || (ck2 == false)) { if (!ck1 && _list1[i] == -1)
Außerdem habe es gemacht sowie du gesagt hast mit der h.datei ecc. aber kriege diese Fehlermeldung:
ListProcessing.cpp: In member function ‘void ListOfIntegers::interLeaveListOfIntegers(ListOfIntegers&, ListOfIntegers&)’: ListProcessing.cpp:36: error: no match for ‘operator[]’ in ‘_list1[i]’ ListProcessing.cpp:43: error: no match for ‘operator[]’ in ‘_list2[i]’
Dario 25Mai10 19:23
@Dario: Du übergibst jetzt keine int* mehr, sondern zwei ListOfIntegers. Also muss in deiner .h-Datei stehen: void interLeaveListOfIntegers(const ListOfIntegers& list1, const ListOfIntegers& list2);) Grüße, Florin 25Mai10 18:17
Hallo, ich habe ein kleines Problem:
ListProcessingMain.cpp: In function ‘int main(int, char**)’: ListProcessingMain.cpp:32: error: no matching function for call to ‘ListOfIntegers::interLeaveListOfIntegers( ListOfIntegers&, ListOfIntegers&)’ ./ListProcessing.h:30: note: candidates are: void ListOfIntegers::interLeaveListOfIntegers(int*, int*)
das ist die Fehlermeldung. P.S. was heisst diese & am Ende von ListOfIntegers? Meine interleave Funktion
void interLeaveListOfIntegers(int* list1, int* list2)
und die Mainfunktion
lista.interLeaveListOfIntegers(list1, list2);
Ich verstehe nicht wie ich die Parameter anpassen soll.. list1 und list2 sind die zwei Objekten-elements (oder listen) die man aus char* erzeugt und haben schon eine definierte _size ohne Maxima.. Gruß Dario 25Mai10 14:42
@Niklas: Ja, stimmt, schreiben Sie sich einfach eine get(int i) Funktion. Oder benutzen sie pop_back() wie von Sebastian vorgeschlagen, aber get wäre schon natürlicher. Eine dritte Alternative wäre in ListOfIntegers.h vor die Deklaration von parseFromString folgende Zeile zu schreiben
FRIEND_TEST(ListOfIntegersTest, parseFromString)
Das habe ich in der Vorlesung nicht erklärt, aber Sie dürfen es gerne benutzen, weil es eigentlich die Methode der Wahl ist. Damit geben Sie dem TEST(ListOfIntegersTest, parseFromString) die Rechte, auf die Membervariablen eines ListOfInteger Objektes zuzugreifen, insbesondere die _elements. Hannah 24Mai10 21:42
Das lässt sich mittels der pop_back Methode realisieren. SebastianD 24Mai10 16:47
Ok, noch eine Frage zu den Tests: Mir fällt irgendwie kein sinnvoller Test für die parse Funktion ein, der nicht die einzelnen Einträge der Liste anschauen muss. Dann bräuchte ich aber wieder eine Get() Funktion. Stehe ich da auf dem Schlauch oder ist das wirklich ein Problem? Niklas 24Mai 15:59
@Dario: Der constructor wird aufgerufen, wenn das Objekt deklariert und damit effektiv im Speicher erzeugt (konstruiert = constructed) wird. Aufgabe des Konstruktors ist es typischerweise, die Membervariablen des Objektes geeignet zu initialisieren. Der destructor wird aufgerufen, kurz bevor das Objekt aus dem Speicher gelöscht (zerstört = destructed) wird. Die Aufgabe des Destruktors ist typischerweise Aufräumen und schauen, dass aller Speicher der zu Lebzeiten des Objektes alloziert wurde auch wieder freigeben wird. Von daher schon nicht schlecht die Namen. Hannah 24Mai10 14:36
@Niklas: Erstmal keine Änderung gegenüber vorher, also ein TEST pro Methode und der heißt dann etwa TEST(ListOfIntegersTest, parseFromString). Hannah 24Mai10 14:32
Hallo, wenn ich das richtig verstanden habe werden Tests in Gtest ja so erstellt TEST(<Filename>, <Functionname>). Wie sieht das denn mit Klassen ordentlich aus? Checkt man da alle Funktionen in einem Test? Gruß Niklas 24Mai 14:18'
Also ich wollte nur eine kurze Frage stellen. Constructors und Deconstructors sind im Endeffekt nichts anders als Funktionen , die automatisch aufgerufen werden bzw. am Anfang der Klasse und eine am Ende der Klasse, wenn ich ein Objekt erstelle. Aber was wird "erzeugt und eliminiert"? Hätte nicht der Erfinder von c++ anders nennen können? Gruß Dario 23Mai 16:06
@Heinke: Nach dem Aufruf von parseFromString soll _size schon auf dem richtigen Wert stehen. Sie müssen den Wert da ja sowieso schon wissen, damit Sie, wie in der Aufgabenstellung gefordert, genau die richtige Menge Platz für den _elements pointer allozieren können. Wie Sie das machen, dafür gibt es viele Möglichkeiten. Eine davon ist, einfach vorab die Anzahl der Kommas im Argument listAsString zu zählen. Wenn das Argument eine korrekt formatierte Liste enthält ist die Anzahl der Elemente ja einfach die Anzahl der Kommas plus eins. Und wenn Sie beim Parsen der Liste herausfinden, dass Sie nicht korrekt formatiert ist, dann geben Sie den Platz einfach wieder frei und setzen size = 0, weil in dem Fall ja (nach wie vor) die leere Liste zurückgegeben werden soll. Eine andere Möglichkeit wäre, vorab einfach Platz für soviel ints zu reserviere wie das Argument listAsString lang ist (d.h. wieviele Zeichen es hat). Denn mehr Zahlen können ja nicht drin stehen. Am Ende vom Parsen wissen Sie ja dann wieviele ints tatsächlich drin standen und dann können Sie die genau passende Menge Platz allozieren und einmal umkopieren. So, das waren jetzt zwei Möglichkeiten, die mir spontan einfallen, aber es gibt bestimmt auch noch viele andere. Hannah 23Mai10 14:23
Kann ich einfach ne weitere Methode schreiben, die die Länge der Liste zurück gibt, die sie haben wird, wenn sie geparsed ist (also die orkommenden Zahlen zählt) und diesen Wert dann den Methoden für interleave und parse geben, damit _size entsprechend gesetzt wird? Oder gibts noch einen supergenialen Weg, der mir nur noch nicht eingefallen ist, weil ich nicht supergenial bin? Heinke 23Mai10 14:14
@Roman: Ja, richtig, kann praxisrelevant sein, muss aber nicht. Vielleicht kommen wir ja irgendwann gegen Ende des Semesters dazu. Freut mich auf jeden Fall, dass Sie sich für diese weiterführenden Konzepte interessieren und sich da offenbar auch schon sehr gut auskennen. Hannah 20Mai10 21:44
@Hannah: Ich wollte auf gar keinen Fall dogmatisch rüber kommen, aber als rein theoretisch würde ich gerade das KISS-Prinzip nicht sehen. Klassen die mehr als nur die essentiellen Eigenschaften/Methoden eines Objektes implementieren haben auf lange Sicht praxisrelevante Nachteile die mMn nicht vernachlässigbar sind, da die Klassen riesig werden und unintuitiv. Auch könnte man die getInterleaveOf Methode in der ListHandler Klasse abstrahieren und z.B. unabhängig von dem genauen Typ der Liste machen (z.B. per interface). Derjenige der seine interleaveWith Methode in der Liste selber implementiert kann diese Methode nun für jede andere Form von Listen kopieren (und bei irgendwelchen Änderungen ALLE Methoden ändern..). Dass das über den momentanten Stand in der Vorlesung hinausgeht is mir klar, aber die Praxis Relevanz sehe ich da trotzdem ganz deutlich. RomanW 20Mai10 21:32
@Roman: Mit "keine Methode ... sein sollte" und "ausgelagert sein sollte" wäre ich vorsichtig. Es gibt viele schöne Konzepte in der objekt-orientierten Welt, nur was die dann mit der Praxis zu tun haben, ist oft fraglich. Ich mache in der Vorlesung ganz dezidiert Programmieren in C++ aus der Praxis für die Praxis und so soll es sein und so soll es auch bleiben. Weiterführende Konzepte werden wir genau dann lernen und anwenden, wenn wir sie wirklich brauchen, vorher nicht. Hannah 20Mai10 21:07
@SebastianD: Die Konfusion kommt höchstwahrscheinlich daher, dass interleaveWith (imo!) streng genommen keine Methode der ListOfInteger Klasse sein sollte, sondern (gemäß dem KISS-Prinzip) in einer Art ListHandler Klasse ausgelagert sein sollte. Diese würde dann eine Methode a la ListOfIntegers getInterleaveOf(ListOfIntegers list1, ListOfIntegers list2) bereitstellen und die neue Liste zurückgeben. RomanW 20Mai10 20:53
@Ben: private bedeutet nicht Instanz-, sondern Klassensichtbarkeit. Du kannst also innerhalb deiner Listenklasse auf die (private) Member anderer Instanzen der Listenklasse zugreifen. SebastianD 20Mai10 20:19
@Hannah: Es ging mir prinzipiell nur um die Interleave Methode, da habe ich von außen keinerlei Zugriff auf die Listen in den übergebenen Objekten, da _size und _elements private ist. Somit muss man entweder get/set Methoden erstellen um die Werte einzelt auslesen zu können, die Klassenvariablen public machen oder die Methoden vom zweiten Teil nutzen (push_back/pop_back), wobei jedoch direkt bei der leeren Liste ein assert kommt, den ich nicht abfangen kann. Es war von mir weniger eine Frage sondern mehr eine Feststellung Ben 20Mai10 19:38
@Ben: Auf die Membervariablen _size und _elements brauchen Sie für dieses Übungsblatt keinen Zugriff von außerhalb der Klasse. Deswegen können Sie auch private sein (sollten Sie sowieso) und Sie brauchen auch keine spezielle get oder set Methode. Nur die Memberfunktionen brauchen Zugriff auf diese Membervariablen, und den haben Sie ja sowieso, d.h. Sie können z.B. in parseListOfIntegers einfach schreiben _size = listSize oder sowas. Hannah 20Mai10 19:28
@Heinke: Ja, genau, siehe mein code snippet in der Antwort an SebastianD. Hannah 20Mai10 19:23
@SebastianD: Berechtigte Frage. Ich würde es so machen:
void ListOfIntegers::getInterleaveOf(const ListOfIntegers& list1, const ListOfIntegers& list2);
und dann in der main Funktion:
ListOfInteger list1; ListOfInteger list2; list1.parseFromString(list1AsString); list2.parseFromString(list2AsString); list1.print("Input list 1 : "); list2.print("Input list 2 : "); ListOfInteger result; result.getInterleaveOf(list1, list2); result.print("Result list : ");
Die Version von Ben ist aber auch eine Variante die man in diesem Kontext öfter sieht. Ich würde die Methode dann allerdings interleaveWith nennen, man sollte das bei der objekt-orientierten Programmierung immer wie einen (einfachen) Satz lesen könnten. Die Variante hat halt den Nachteil, dass dann die eine Liste überschrieben wird, deswegen gefällt mir die oben besser. Hannah 20Mai10 19:14
@Hannah: Ah. Verstehe. Mit anderen Worten, ich muss also für jede Liste eine Instanz des Objektes erstellen. Oder sehe ichs immer noch falsch? Heinke 20Mai10 18:23
Für mich klingt es nach Version 1:
ListProcessing list1; [...] ListProcessing list2; [...] list1.interleave(list2);
Nur muss man sich dann imho Gedanken über die Sichtbarkeit von _size und _elements machen oder eine set/get Methode implementiern...Ben 20Mai10 17:36
Ich bin mir im Unklaren über die genaue Funktionsweise der neuen Interleave-Methode, da mir selbst spontan mehrere verschiedene Möglichkeiten einfallen:
1. void interleaveWith(ListOfIntegers list); // Die Elemente dieser Liste werden mit der Argumentliste vermischt (oder was auch immer).
2. ListOfIntegers interleaveWith(ListOfIntegers list); // siehe 1., nur dass die Argumente jetzt in einer neuen Liste gespeichert und diese zurück gegeben wird.
3. void interleave(ListOfIntegers list1, ListOfIntegers list2); // Speichert die Elemente der beiden Argumentlisten vermischt in dieser Liste (Liste vorher leeren?).
4. ListOfIntegers interleave(ListOfIntegers list1, ListOfIntegers list2); // Idealerweise sogar static. Speichert die Elemente der beiden Argumentlisten vermischt in einer neuen Liste und gibt diese zurück.
5. void interleaveWith(ListOfIntegers result, ListOfIntegers list); // C-Style. Man übergibt außerdem eine Liste, in der die Elemente dann gespeichert werden sollen.
6. ...
Welche davon? SebastianD 20Mai10 14:24
@Heinke: Für Aufgabe 1 vom neuen Übungsblatt soll das Programm exakt dasselbe machen, die Ihr Programm vom 4. Übungsblatt, nur soll das Programm mit Klassen realisiert sein, wie in der Vorlesung vorgemacht, und die Felder (die jetzt Membervariablen sind), sollen keine fixe Größe MAX_LIST_SIZE mehr haben, sondern genau die Größe, die benötigt wird. Beantwortet das Ihre Frage? Hannah 20Mai10 12:46
Verstehe ich das richtig: Der Benutzer soll ./ListProcessingMain "1,1,1,1" "2,2,2,2,2" aufrufen und anschließend sollen die Listen intern geparsed, interleaved und als array im Objekt gespeichert werden? Heinke 20Mai10 9:28