als Rückgabe eine tabelle
-
Hallo,
ich stehe gerade vor folgendem Problem.
Ich bekomme durch eine for- schleife eine tabelle mit chars geliefert, die ich mit
while((row=mysql_fetch_row(result)) != NULL) { if(row) for(spalte=0;spalte<cols;spalte++) cout<<row[spalte]; cout<<enld; }ausgeben kann.
Nun möchte ich aber diese Tabelle irgendwie in ein string array umwandeln das ich als rückgabewert von einer funktion behandeln kann. Zeilen und spalten übergebe ich per referenz an die funktion.
Habt ihr eine idee wie ich die verwirklichen könnte?
Mein Ansatz:
typedef struct { char a[10], b[50], c[10], d[20]; }tabelle;aber wie kann ich da in der forschleife a, b ,c oder d ansprechen?
Und dann wäre es ja auch nur eine zeile...
Hoffe mein problem kam verständlich rüber.
Bin echt am grübeln, aber alles was mir einfällt, erscheint mir sehr sehr umständlich.Gruß Gustl
-
Schreib alles in einen std::string und unterteile die Zeilen mit einem '\n'.
-
ja, dann müsste ich aber den rückgabewert string wieder so trennen wie die werte ursprünglich in der tabelle waren. und da in der tabelle auch strings mit leerzeichen sind ist dies auch sehr umständlich.
Habe auch schon so überlegt:
tabelle TMP; for(spalte=0;spalte<cols;spalte++) { if(spalte == 0) strcpy(TMP.a, row[spalte]); if(spalte == 1) strcpy(TMP.b, row[spalte]); if(spalte == 2) strcpy(TMP.c, row[spalte]); ...usw... return TMP; }so könnte ich es machen, obwohl dies nicht besonders elegant ist.
Aber dann fehlen immernoch die zeilen... und die können eben sehr viele werden.
Spalten begrenzen sich auf höchstens 5.
-
warum willst du auf die einzelnen Zelleninhalte mit einer For-Schleife zugreifen? Klingt für mich nicht ganz logisch. Ich üwrds vermutlich in etwa wie folgt machen:
struct Zeile //typedef struct ist C-Sytle und in C++ out... { string Feld_0; //char-arrays sind in C zwar üblich, in C++ kann man besser std::string nehmen short Feld_1; string Feld_2; long Feld_3; }; typedef std::vector<Zeile> Tabelle;/edit ich seh grad noch strcpy() - das ist auch C. Bist du sicher dass du im richtigen Forum bist?
-
pumuckl schrieb:
warum willst du auf die einzelnen Zelleninhalte mit einer For-Schleife zugreifen? Klingt für mich nicht ganz logisch. Ich üwrds vermutlich in etwa wie folgt machen:
Weil ich, bis jetzt, keine andere möglichkeit kenne die sql daten auszulesen, als ich oben mit der while schleife genannten.
pumuckl schrieb:
/edit ich seh grad noch strcpy() - das ist auch C. Bist du sicher dass du im richtigen Forum bist?
ja, das war jetzt nur so, quasi hingeschmiert^^
Aber danke, die idee mit dem vector ist echt nicht schlecht... echt klasse.
Danke dir.

Gruß
Gustl
-
Fuer wenig komplexe Sachen koennt man die dinger durchaus in nen Array schreiben ... wobei Arrays zurueckgeben immer so ne sache ist ...
Am besten C-Like in nen Puffer schreiben lassen ...Fuer komplexere Dinge wird ich ne Klasse nehmen, die die Daten verwaltet (ohne referenzen zu benoetigen) und kopierbar ist (CCTor / = operator, die auch wirklich tiefe Kopien machen).
Wirklich performant wird das aber dann ned ... da sicher viel im Speicher hin und hergeschoben wird.
Vielleicht kannst du dein Problem umgestalten, so das du auf ne Eventschnittstelle kommst ....
Also quasi nen Verarbeitungsobject bekommt, was deine Datan "parst"/"verarbeitet" und fuer jedes einzelergebniss (also Zeile/Spalte aka Zelle) nen event wirft, was von nem Modell abgefangen wird und dann bei dir verarbeitet / angezeigt wird.Ciao ...
-
RHBaum schrieb:
Fuer wenig komplexe Sachen koennt man die dinger durchaus in nen Array schreiben ... wobei Arrays zurueckgeben immer so ne sache ist ...
Am besten C-Like in nen Puffer schreiben lassen ...Wenns ein dynamisches Array sein soll ist std::vector genau das. Wenns um ein statisches Array mit fester Größe gehen soll, dann ist std::tr1::array genau das. Der Overhead gegenüber C-Arrays ist bei beiden minimal bis nicht vorhanden und wird durch die Vermeidung der unbequemen und z.T. unsicheren Handhabung der C-Arrays zigfach wettgemacht.
-
Ich werde es dann mit vector realisieren, erscheint mir am einfachsten und auch elegant.
nochmal, danke.
-
BTW: wenn du grössere Datenmengen in einem std::vector zurückgeben willst, dann könnte es sich u.U. auszahlen, den vector in einem boost/tr1::shared_ptr zu verpacken.
std::vector kann eben (noch) keine move-Sekamtik, und kann daher relativ teuer als Returnwert sein (weil u.U. kopiert wird).
-
hustbaer schrieb:
std::vector kann eben (noch) keine move-Sekamtik, und kann daher relativ teuer als Returnwert sein (weil u.U. kopiert wird).
Hmm. Letztes Mal wurde mir mehr oder weniger gesagt, RVO würde hier das Richtige tun. Vielleicht antwortete auch deshalb niemand mehr spezifisch, als ich nochmals nachfragte.

Ich bin nach wie vor der Ansicht, man sollte sich bei Rückgabetypen nicht darauf verlassen, dass keine unnötigen Kopien angelegt werden. Also bei grösseren Objekten eher Referenzparameter benutzen. Wie sieht es nun wirklich aus?
-
Nexus schrieb:
Wie sieht es nun wirklich aus?
Es sieht so aus, dass du dich tatsächlich nicht darauf verlassen kannst. Referenzparameter würde ich trotzdem nicht benutzen, eher Proxy-Objekte (oder smart-Pointer wie von hustbaer vorgeschlagen).
Der Grund ist ganz einfach Lesbarkeit/Verständlichkeit des Codes. Als Leser erwartet man dass Ergebnisse einer Funktion auch tatsächlich als Rückgabewerte zurückgegeben werden, nicht durch die Modifizierung eines in/out-Parameters.
-
pumuckl schrieb:
Als Leser erwartet man dass Ergebnisse einer Funktion auch tatsächlich als Rückgabewerte zurückgegeben werden, nicht durch die Modifizierung eines in/out-Parameters.
Kommt aber auch drauf an.
Wenn ich so eine Funktion habe:
void FillVector(std::vector<MyClass>& Vec);kann ich mir etwa denken, was die Funktion macht. Zumindest hat man da keinen unnötigen Overhead durch Referenzzählung oder dynamische Allokation (auch wenn das im Verhältnis zu einem grossen Container nicht viel ausmacht). Bei einem
shared_ptrals Rückgabe frage ich mich persönlich viel eher, da ich da an geteilten Besitz denke.Aber naja, das kommt wohl auch auf den Betrachter an...
-
Wenn deine Funktion tatsächlich nur als Modifikator des Vector gedacht ist, bietet es sich evtl. auch an, den vector sowohl als Referenz zu übernehmen als auch ihn danach wieder zurückzugeben (auch wenn man das Funktionsergebnis dann nicht unbedingt verwendet).
Ist die Funktion eine Erzeugende des vector, dann wäre es ungünstig vom Aufrufer zu verlangen, selber einen vector zu erzeugen und ihn zu übergeben. An Stelle des shared_ptr gibts natürlich andere smartpointer, die Besitzübergabe implementieren an Stelle von geteiltem Besitz (z.B. auto_ptr).
-
Nexus schrieb:
hustbaer schrieb:
std::vector kann eben (noch) keine move-Sekamtik, und kann daher relativ teuer als Returnwert sein (weil u.U. kopiert wird).
Hmm. Letztes Mal wurde mir mehr oder weniger gesagt, RVO würde hier das Richtige tun. Vielleicht antwortete auch deshalb niemand mehr spezifisch, als ich nochmals nachfragte.

Ich bin nach wie vor der Ansicht, man sollte sich bei Rückgabetypen nicht darauf verlassen, dass keine unnötigen Kopien angelegt werden. Also bei grösseren Objekten eher Referenzparameter benutzen. Wie sieht es nun wirklich aus?
- kannst du dich nicht darauf verlassen
- gibt es Fälle, wo (N)RVO garnicht greifen kann:
void foo() { std::vector<std::string> vec; // ... use vec ... vec = bar(); // keine Chance für (N)RVO! // ... use vec ... }(Mit "greifen kann" meine ich nicht dass RVO nicht trotzdem verwendet werden kann um das Temporary zu initialisieren, sondern dass danach trotzdem der assignment operator laufen muss, und der Aufruf damit erst wieder unnötig teuer wird)
Natürlich könnte man solche Stellen umschreiben, so dass (N)RVO wieder möglich ist:
void foo() { std::vector<std::string> vec; // ... use vec ... std::vector<std::string> temp(bar()); vec.swap(temp); // ... use vec ... }Der Nachteil ist allerdings, dass man daran denken muss, es immer so zu machen.
----
z.T.
auto_ptr: ja, könnte man auch verwenden. Ich persönlich verwende halt liebershared_ptralsauto_ptr. Andrerseits hatauto_ptreinen klaren Vorteil gegenübershared_ptr: man bekommt die Ownership "wieder zurück" wenn man möchte (T* myPrecious = autoPtr.release();).Ob so eine Optimierung Sinn macht oder nicht ist natürlich wieder die andere Frage. Wenn man genau eine Ebene hat durch die der std::vector als Returnwert durchgereicht wird, und die Daten ursprünglich z.B. aus einer Datenbank kommen, dann wird man den Unterschied vermutlich nicht spüren! Und sollte daher auch eher auf solche Optimierungen zerzichten
