AD Teaching Wiki:

Fragen und Kommentare zur 5. Vorlesung / zum 5. Übungsblatt

Erstmal danke für die schnelle Hilfe :) @Johannes: also kopiert habe ich's aber die Kopie hatte sein eigenes Unterordner. Aber ja es versuchte an der falschen Stelle zu commiten, da es sich den Original-Pfad in den Konfigdateien gemerkt hatte... Nächstes mal werde ich einfach gleich den .svn/ Ordner in der Kopie löschen, und dann adden damit auch alle Pfade stimmen. JonathanB 2Jun10 12:34

@Jonathan: Ja, wenn da eine Liste mit den Dateien kommt, dann heißt das, dass es prinzipiell geht, also der Fehler nicht bei uns liegt, sondern irgendwas mit Ihrer Arbeitskopie durcheinander geraten ist. Das kann mitunter schwer zu fixen sein, wenn man sich mit SVN nicht sehr gut auskennt. Dann ist es manchmal das Beste, an einer ganz neuen Stelle ganz neu auszuchecken. Hannah 2Jun10 12:25

Da kommt eine Liste mit den Dateien aus der Vorlesung. Sollte dies nicht so sein? Ich habe aber gerade mein Problem gelöst indem ich mein Blatt aus dem svn entfernt habe, den .svn/ Ordner entfernt, und neu geadded/commitet. Ich glaube es lag daran, dass ich den Ordner vorlesungen-5/ einfach kopiert habe, und dadurch die svn Konfigurationsdateien durcheinander ging. JonathanB 2Jun10 12:22

@JonathanB: Ich kenn mich zwar nicht wirklich aus: aber bei dir steht ja der vorlesungen/vorlesung-5-Link, kann es sein dass du einfach die Vorlagen aus der Vorlesung verändert hast und diese jetzt commiten willst? Dann versucht svn ja die Änderungen in dem Ordner vorlesungen/vorlesung-5 durchzuführen und das ist nur Frau Bast erlaubt. Wenn dem so ist, kopier doch mal alles in den Ordner in dem deine anderen Übungsblätter sind, adde den Ordner und commite. JohannesM 02Jun10 12:15

@Jonathan: Was passiert wenn Sie auf http://ad-svn.informatik.uni-freiburg.de/teaching/cplusplus-ss2010/vorlesungen/vorlesung-5 klicken und Ihren RZ-Account und Ihr Passwort eingeben? Im Zweifelsfall bei Jens Hoffmann vorbeischauen, s.u. Hannah 2Jun10 12:15

Ich habe das gleiche Problem wie Sven, irgendwie versteh's ich auch nicht.

Sending        uebungsblatt-5/ListOfIntegers.cpp
svn: Commit failed (details follow):
svn: Server sent unexpected return value (403 Forbidden) in response to CHECKOUT request for '/teaching/cplusplus-ss2010/!svn/ver/2609/vorlesungen/vorlesung-5/ListOfIntegers.cpp'

Wieso wird beim Checkout ein Fehler geworfen? ich mache ja kein checkout... Ich habe bereits versucht neu auszuchecken, vorlesungen gelöscht, bringt alles nichts. Hat jemand eine Idee? JonathanB 2Jun10 11:55

Ich habe bereits versucht neu auszuchecken, vorlesungen gelöscht, bringt alles nichts. Hat jemand eine Idee? JonathanB 2Jun10 11:55

Danke hat sich geklärt. Würde ja gern erklären wie, aber das weiß ich jetzt selber nicht so genau. - Sven 2.Juni 9:25

@Sven nochmal: Klicken Sie doch mal auf den Link in Ihrer Frage im Webbrowser und geben Sie dann Ihren RZ Accountnamen und das zugehörige Passwort ein. Wenn dann eine Seite mit einer Liste der Dateien kommt, liegt es an Ihrer Arbeitskopie. Hannah 2Jun10 00:50

@Sven: hast du vielleicht an einem alten Übungsblatt etwas verändert? Dann versucht SVN nämlich das alte Übungsblatt nochmal zu commiten... und das ist (403 Forbidden). War bei mir jedenfalls so :D JohannesM 02Jun10 00:45

@Sven: Hat Ihr SVN vielleicht einen falschen Benutzernamen gespeichert und nicht den von Ihrem RZ Account? Machen Sie mal ein --username=IHR_RZ_USER_NAME und geben Sie dann das Passwort für Ihren RZ Account ein. Ich habe gerade in unserer svn_access_control nachgeschaut, und laut der ist der Unterordner vorlesungen für alle lesbar. Falls Sie das Problem nicht lösen können, einfach morgen mal bei Jens Hoffmann vorbeischauen (Raum 00-027 in Gebäude 51). Hannah 2Jun06 00:36

Hab meinen Fehler gefunden, zumindest, den zu diesem Problem JonathanN 01Juni10 20:43

Hallo, probiere gerade meine Dateien zu commiten. Bekomme dabei folgende Fehlermeldung: "Der Server hat einen unerwarteten Rückgabewert (403 Forbidden) in Antwort auf die Anfrage OPTIONS für http://ad-svn.informatik.uni-freiburg.de/teaching/cplusplus-ss2010/vorlesungen/vorlesung-5 zurückgeliefert". Kann mir da jemand weiterhelfen? Sven 1Jun10 20:27

@Bettina: Ja, nur _size um eins verringern ist schlau und tut's schon. Sie müssen bei pop_back ja nicht den Speicher neu allozieren und was in dem unbenutzten Speicher steht ist ja egal. Das assert(_size > 0) ist schon richtig, wenn die Liste dann beim Aufruf leer ist, stimmt die Bedingung nicht und das Programm wird beendet, mit dem Hinweis dass die Bedingung in dem assert nicht erfüllt ist, das nennt man assert failure. Hannah 1Jun10 17:55

Meine Frage betrifft pop_back(): Reicht es, einfach _size um eins zu verringern, um das letzte Element zu entfernen? Dann ist das letzte Element ja quasi nicht mehr da, wenn ich es beispielweise mit print() ausgeben möchte. Oder muss ich mit dem letzten Eintrag in _elements noch etwas machen? Und was genau ist mit assert failure gemeint? Ich habe in pop_back() ein assert(_size > 0); Gibt es eine Möglichkeit, das auch zu testen, wenn man aus einer leeren Liste zu entfernen versucht? Bettina 1Jun10 16:43

@Martin: Um _elements trotzdem einlesen zu könne, können Sie FRIEND_TEST benutzen, siehe meinen Eintrag Hannah 24Mai10 21:42 unten. Die Elemente mit pop_back auszulesen finde ich nicht gut, da pop_back ja die Liste verändert, und sie die Elemente eigentlich nur lesen wollen. Wenn schon, dann eine Methode getElement wie auch in dem erwähnten Eintrag beschrieben. Hannah 1Jun10 12:08

@Hannah: Da _elements private ist, kann man ja ohne weiteres es nicht direkt testen. Daher dachte ich daran, _elements mit der pop_back()-Methode auszulesen.(dh. Blackbox-Test, weil ich nicht direkt auf die private-Variable zugreife, sondern über eine public-Methode darauf schließe) Wenn ich nun eben allerdings eine leere Liste "pop_backen" will gibt es eben einen assert-failure. Ein Möglichkeit (die Frage ist, ob das ok ist) wäre das pop_back -1 zurückgibt, falls die Liste bereits leer ist. MartinG 01Juni10 09:22

@Martin: Zu Ihrer ersten Frage. Ja, gute Frage, sie haben ja jetzt die Auswahl zwischen der leeren Liste (also einer regulären Liste, die einfach keine Elemente enhält, also _size == 0) und einer undefinierten Liste (wo der Listenzeiger NULL ist). Ich überlasse es Ihnen, für welche von den beiden Sie sich entscheiden, würde aber die undefinierte Liste natürlicher finden. Was hat denn beim Testen auf NULL nicht funktioniert? Wenn ich mich recht erinnere macht ASSERT_EQ(_elements, NULL) Probleme. Sie können stattdessen einfach schreiben ASSERT(_elements == NULL). Ihre zweite Frage verstehe ich nicht. Hannah 31Mai10 22:36

Bei Fehlern im char-array für die parse-Methode soll ja eine leere Liste "zurückgegeben" werden. Letztes Mal war das ja einfache eine Liste mit -1 an erster Stelle. Wie sieht das diesmal aus? Bedeutet leer Initialzustand oder Zustand nach Destruktion, oder was ganz anderes (also wie sollen _elements _size und _capacity belegt sein) Und natürlich wie kann man darauf testen? (Auf NULL testen hat bei mir nicht funktioniert). Außerdem: Man kann Aufgabe 1 auch mit den Methoden von Aufgabe 2 black-boxed testen oder? MartinG 31Mai10 22:29

@Hannah: Danke, ich hatte mehrere Fehler, zuerst hab ich vergessen #include <gtest/gtest.h> zu machen. Auch habe ich jetzt die Variante mit FRIEND_TEST benutzt, musste aber etwas im Wiki stöbern, deshalb die Frage: Wäre es möglich das Wiki etwas genauer zu unterteilen, zB: eine große Überschrift erste Teilaufgabe, darunter alle Einträge die etwas mit der ersten Aufgabe zu tun haben usw. Gruß Robin 30Mai10 15:08

@Robin: Haben Sie #include <gtest/gtest.h> gemacht? Außerdem sollte es ListOfIntegersTest heißen. Hannah 30Mai10 14:08

@Hannah: Die Fehlermeldung bezieht sich auf die erste Zeile:

TEST(ListOfIntegers, parseList)

Robin 30Mai10 13:33

@MartinS: Das genze kannst du in der Dokumentation von gtest genauer nachlesen: http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. Schau dort einfach unter der Überschrift private Class Members nach. Man muss allerdings etwas aufpassen, weil dort Quelltext aus zwei Dateien steht, und es so aussieht, als ob es in einer stünde (man beachte die Kommentare). Wenn du das ganze für deine Tests umschreibst, sollte es eigentlich funktionieren. Hier Mal zusammengefasst, was ich bei mir änder musste, damit friend-Test funktioniert: Header:

//sinnvollerweise nach der header-Guard
#include <gtest/gtest_prod.h>
//...
class ListOfIntegers
{
//...
private: 
 FRIEND_TEST(ListProcessing, parseList); 
//oder halt genau das was bei deinem TEST zwischen den Klammern steht zwischen die Klammern setzen
// ... 

Die Alternative währe, analog zur header-guard eine eigene Konstante einzuführen, die durch ihr Vorhanden-sein einige Methoden von ListOfIntegers public statt private macht. Codebeispiel

// Im Test-Quelltext
//...
#define LIST_PROCESSING_USAGE_TEST
#include "./ListProcessing.h"
//...

//in ListProcessing.h
//...
class ListOfIntegers
{
public:
#ifdef LIST_PROCESSING_USAGE_TEST
//hier kommen alle Methoden/Variablen rein, die man im Test public braucht, sonst aber private haben will
#endif
// weitere public-Methoden
private:
#ifndef LIST_PROCESSING_USAGE_TEST
// nochmal die gleichen Methoden wie oben zwischen den ifs
#endif
// weitere Private-methoden
}
//...

Friendtest sollte aber die sauberere Lösung sein. Fabian 30 Mai10 13:09

@Martin: Wenn Sie FRIEND_TEST benutzen, müssen Sie am Anfang der Datei ein #include <gtest/gtest.h> machen, weil da drin ist das FRIEND_TEST definiert. Hannah 30Mai10 13:05

@Robin: Auf welche Zeile in Ihrem Codeschnipsel bezieht sich die Fehlermeldung? Hannah 30Mai10 13:03

Ich würde gerne meinen Test mit der "Friend-Variante" gestalten, da ich den ganzen Code schon geschrieben habe und es bisher auch noch nicht für sinnvoll erachte eine getELement() Methode zu schreiben, nur damit der Test funktioniert. Leider klappt es bei mir nicht mit der "Friend-Methode". Mein CODE in der Headerdatei:

// Parse a list from String
FRIEND_TEST(ListOfIntegersTest, parseFromString);
void parseFromString(const char* listAsString);

Die Fehlermeldung beim compilieren

./ListOfIntegers.h:19: error: ‘ListOfIntegersTest’ has not been declared
./ListOfIntegers.h:19: error: ‘parseFromString’ has not been declared
./ListOfIntegers.h:19: error: ISO C++ forbids declaration of ‘FRIEND_TEST’ with no type

@Dario: Die Warnung, dass ein anderer Benutzer gerade editiert hat tatsächlich einen Sinn. ;-) MartinS 30Mai10 11:21

Hast schon mal getElemente(0)...(1)...(2) ,anstatt getElement[0]...[1]....[2] probiert? Dario 30Maio10 11:19

Hallo, ich habe Probleme mit dem Test erstellen, in der Test Datei habe ich folgendes:

TEST(ListOfIntegers, parseList)
{
  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]);
}

in der Konsole kriege ich folgende Fehlermeldung:

ListOfIntegersTest.cpp:6: error: expected constructor, destructor, or type conversion before ‘(’ token
make: *** [ListOfIntegersTest.o] Error 1

Ich kann nicht viel mit dieser Fehlermeldung anfangen, aber vielleicht weiß jemand woran das liegt. Gruß Robin 30 Mai10 9:20

@Markus: Wenn Sie unbedingt wollen und wenn die Funktion / Methode für sich alleine Sinn macht, habe ich nichts dagegen. Es gibt aber ein anderes, ebenso wichtiges Prinzip: nie komplizierter als nötig. Jede zusätzliche Funktion ist eine Indirektion, wo man im Code erst nachschauen muss, aha uns was macht die Funktion jetzt? Wenn diese Funktion an mehreren Stellen unabhängig voneinander benutzt wird, macht das Sinn und die Indirektion ist gerechtfertigt. Ansonstem schreibt man den Code lieber an Ort und Stelle. Mit einem vernünftigen Kommentar über dem entsprechenden Codeblock natürlich. Hannah 29Mai10 23:37

Dürfen wir eigene Funktionen hinzufügen wenn wir sie für sinnvoll erachten? Ich denke da so an allocate(), grow() und dergleichen. Fände ich im Zuge des OOP Ansatzes jedenfalls wesentlich besser. MarkusN 29Mai 20:44

@Sebastian: Hallo Sebastian, das ist mir gestern auch eingefallen und das lag daran, dass ich die Ferien bei der Erstellung des Skripts nicht bedacht habe. Das sollte aber nun funktionieren :). Ina 28Mai10 12:20

@Dario: Die Funktionen parseFromString und push_back und pop_back sind völlig unabhängig voneinander. Man macht parseFromString um die Zahlen, die in der Liste gespeichert sein sollen, aus einer Zeichenkette zu lesen. push_back und pop_back fügen einfach einer schon gegebenen Liste ein Element hinzu bzw. nehmen eins weg, ganz egal wo diese Liste herkommt und wie sie erzeugt wurde. Hannah 27Mai10 23:21

Ich bin davon ausgegangen, dass eine ListOfIntegers muss einfach immer geparsed werden, was wir immer so gemacht haben. Die _capacity habe auch sie benutzt aber nicht wie im Blatt geschrieben steht. also mein push_back funktioniert auch , habe sie mehrmals getestet. Dario 27Mai10 23.09

@Dario: Wenn Sie das ganze nicht mit _capacity machen, habe ich meine Zweifel, dass Ihre Methoden das machen, was sie tun sollen. Erklären Sie doch mal in drei Sätzen (nicht mehr), wie Sie das Problem gelöst haben ohne _capacity. Hannah 27Mai10 22:57

@Robin: Meiner Meinung nach bedeutet "geeignet" einfach, dass dein Programm mit der anfänglichen _capacity-Belegung bei allen möglichen Aufrufen von Klassen-Methoden funktionieren soll. Außerdem sollte _capacity dabei am Anfang sehr klein sein (auf keinen Fall 5 oder mehr). Wenn _elements mit NULL initialisiert wird, sollte _capacity 0 sein, aber du musst dann beim verdoppeln von _capacity aufpassen (0 * 2 = 0). Alterantiv könnte man sich auch überlegen, _elements als ein-elementige Liste zu initiallisieren (_capacity = 1, _size = 0). Schau vielleicht mal auch mal unter "Hannah 26Mai10 20:21" nach, vielleicht erklärt das auch einen Teil deiner offenen Fragen. Fabian 27 Mai 22:22

Falls ich die Hinweisen nicht folge dann bekomme ich Punktenabzüge oder ist es nicht relevant? und mein Programm und meine Funktionen sollen einfach für dieses Programm richtig laufen richtig? für das nächstes Programm wenn ich ein paar Sachen umstellen muss ist das für die aktuelle Bewertung nicht wichtig oder?( angenommen ,dass wir mit dem ListIntegers weitermachen). Weil ich nämlich einen anderen Weg für diese _capacity benutzt habe. Das Programm läuft gut und dieses mal auch ohne zweites Argument. Dario 27Mai10 22:14

@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: ========

---- /!\ '''Edit conflict - other version:''' ----
00400000-00402000 r-xp 00000000 08:05 35577934 begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting                           /home/daniel/c++/uebungsblatt-5/ListProcessingMain

---- /!\ '''Edit conflict - your version:''' ----

---- /!\ '''Edit conflict - other version:''' ----
00400000-00402000 r-xp 00000000 08:05 35577934 begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting                           /home/daniel/c++/uebungsblatt-5/ListProcessingMain

---- /!\ '''Edit conflict - your version:''' ----

---- /!\ '''End of edit conflict''' ----

---- /!\ '''Edit conflict - other version:''' ----

---- /!\ '''Edit conflict - your version:''' ----
./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 begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting begin_of_the_skype_highlighting              05 35577934      end_of_the_skype_highlighting                           /home/daniel/c++/uebungsblatt-5/ListProcessingMain

---- /!\ '''End of edit conflict''' ----

---- /!\ '''End of edit conflict''' ----
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:

  1. Soll die Aufgabe 1 mit den Methoden aus Aufgabe 2 gelöst werden (spätestens wenn man Aufgabe 2 implementiert)?
  2. Soll in Aufgabe 1 (wenn nicht die push/pop Methoden genutzt werden) auch _capacity angepasst werden?
  3. Soll, falls Punkt 2 eintritt, auch die Regel mit dem verdoppeln der Kapazität greifen?
  4. 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? :D 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

AD Teaching Wiki: ProgrammierenCplusplusSS2010/Blatt5Fragen (last edited 2010-06-02 18:32:17 by Hannah Bast)