PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++ std::string]ist das hier Quatsch?


Gast
2006-07-26, 11:41:31
Hi Leute,

ich habe auf dieser Seite:
http://www.willemer.de/informatik/cpp/fileop.htm
ein Statement gefunden, das für mich keinen Sinn ergibt:

Datenpuffer

Eine Klasse, die als Datenpuffer verwendet wird, sollte natürlich auch alle Daten enthalten. Sobald die Klasse Zeiger enthält, werden Hauptspeicheradressen auf die Daten und nicht die Daten selbst gesichert. Solche Zeiger sind nicht immer offen zu sehen, sondern verbergen sich manchmal hinter Datentypen. So enthält beispielsweise ein Objekt der Klasse string Verweise auf die Zeichenkette, aber nicht die Zeichenkette selbst. Dementsprechend eignet sich für eine Dateipuffer eher ein klassischer C-String, also ein festes Array von char, als ein string oder ein Zeiger auf einen char.


Beispiel

Das folgende Testprogramm sichert den ersten Parameter, mit dem das Programm aufgerufen wurde, in der Datei testdatei. Wird das Programm ohne Parameter aufgerufen, wird der zuletzt abgelegte Name wieder aus der Datei gelesen und auf dem Bildschirm ausgegeben. Das Programm liegt in zwei Versionen vor. In der Version, in der ein C-String zur Aufnahme der Daten in tDaten verwendet wird, funktioniert es einwandfrei. Entfernen Sie dagegen die Kommentarzeichen der Variablendefinition für Daten und kommentieren die bisherige Variablendefinition aus, werden die Daten in einem string-Objekt abgelegt, weil nun die Klasse tStrDaten verwendet wird. Das Programm scheitert, weil die Zeichenkette nicht mehr innerhalb der Grenzen von tStrDaten liegt und damit nicht in die Datei geschrieben wird.

Wird da behauptet, ein std::string enthalte nicht den eigentlichen String, sondern nur einen Zeiger auf selbigen? Das ist doch Blödsinn, oder?

In dem Beispielprogramm steht z.B.

// Hier werden die C++-Strings verwendet. Allerdings enthält
// ein Objekt vom Typ string nicht die eigentlichen Daten.
class tStrDaten
{
public:
void Set(char *para)
{
data = para;
}
void Show()
{
cout << data << endl;
}
private:
string data;
};

Die Zeile data = para müßte doch eigentlich bewirken, daß ein neuer Speicherbereich mit einer Kopie der Zeichenkette, auf die para zeigt, angelegt wird, und nicht bloß der Zeiger para kopiert wird??

Matrix316
2006-07-26, 12:01:39
Also wenn du Zeiger kopierst, sind es nur die Adressen auf den Speicherbereich und nicht die Daten selbst. Ansonsten machen Zeiger keinen wirklichen Sinn, oder?

Gast
2006-07-26, 12:04:26
Matrix316[/POST]']Also wenn du Zeiger kopierst, sind es nur die Adressen auf den Speicherbereich und nicht die Daten selbst. Ansonsten machen Zeiger keinen wirklichen Sinn, oder?der Operator = sollte für die std::string Klasse überladen sein, findest du nicht?

Matrix316
2006-07-26, 12:24:16
Überladen mit was? ;)

Anscheinend sind folgende Sachen gleich:

char *test1 = "Hallo"
std::string test2 = "Hallo"

daraus würde ich ableiten, dass, dass ein String Objekt nur ein Zeiger ist.

Wobei test1 = test2 nicht geht, im Gegensatz zu test2 = test1.

Gast
2006-07-26, 12:30:17
Matrix316[/POST]']Überladen mit was? ;)mit einer Implementierung, die eine Kopie der Daten anlegt, auf die der rechts von = stehende char-Pointer zeigt?

Matrix316[/POST]']
Anscheinend sind folgende Sachen gleich:

char *test1 = "Hallo"
std::string test2 = "Hallo"und das schlußfolgerst du woraus?

Matrix316[/POST]']
Wobei test1 = test2 nicht geht, im Gegensatz zu test2 = test1.und das deutet worauf hin?

Gast
2006-07-26, 12:40:49
ich habe gerade mal in einem Programm folgendes durchdebuggt:

char szString[] = "irgendwas";
char *pcHelp = szString;
std::string sString = pcHelp;

und mir vom Debugger die Addressen anzeigen lassen, auf die gezeigt wurde. szString und pcHelp zeigen auf die gleiche Adresse. Für sString bekam ich ebenfalls eine Adresse angezeigt, die aber war eine ganz andere als für pcHelp, und das nach der Zuweisung, wo also in sString schon "irgendwas" drinsteht.

Daraus folgt: es wird eine Kopie der Daten angelegt, std::string enthält die Daten, nicht nur einen Zeiger auf diese.

Coda
2006-07-26, 12:59:11
std::string hält natürlich nur einen Zeiger auf einen Speicherbereich - anders wäre es schließlich gar nicht möglich diesen zu vergrößern.

Bei einer Zuweisung std::string foo = "test" wird natürlich aber "std::string &operator=(const char*)" von std::string aufgerufen, das den String kopiert und nicht den Pointer.

Edit: Ich glaube es liegt ein Missverständnis vor. Es ist natürlich so dass std::string nicht ins der Klasse selber seine Daten hält sondern auf dem Heap, weshalb in der Klasse nur ein Pointer zu sehen ist. Dennoch verwaltet es seine Daten selber und ist nicht nur eine Referenz auf Strings irgendwo anders. Das würde auch nicht funktionieren, aus vielerlei Gründen.

Was aber eine mögliche Optimierung vieler Stringklassen ist, ist dass sie lazy kopieren, d.h. wenn mann z.B. QString (aus Qt) benützt und dort zwei Strings einander zuweist wird zunächst wirklich nur der Pointer übernommen bis einer der zweien verändert wird.

Matrix316[/POST]']Also wenn du Zeiger kopierst, sind es nur die Adressen auf den Speicherbereich und nicht die Daten selbst. Ansonsten machen Zeiger keinen wirklichen Sinn, oder?
Nix Ahnung - raushalten.

Matrix316
2006-07-26, 15:27:02
Coda[/POST]']


Nix Ahnung - raushalten.

Was sind denn Zeiger? Was für einen Sinn haben Zeiger? Was für einen Sinn würden Zeiger machen, wenn sie (beim zuweisen) neuen Speicherbereich anlegen und Daten hinkopieren?

Matrix316
2006-07-26, 15:35:33
Gast[/POST]']mit einer Implementierung, die eine Kopie der Daten anlegt, auf die der rechts von = stehende char-Pointer zeigt?

und das schlußfolgerst du woraus?

und das deutet worauf hin?

1. Wurde ja schon geklärt.

2. Weil cout << test1; und cout << test2; das gleiche Ergebnis liefern? Wobei intern scheints ja ein wenig anders zu sein...;)

3. Dass ein String Objekt etwas anders als ein char * Zeiger ist. :rolleyes: Wobei vom Handling und so, ist ja immer noch ein Zeiger. ;)

Coda
2006-07-26, 16:08:44
Matrix316[/POST]']Was sind denn Zeiger? Was für einen Sinn haben Zeiger? Was für einen Sinn würden Zeiger machen, wenn sie (beim zuweisen) neuen Speicherbereich anlegen und Daten hinkopieren?
Du hast keine Ahnung von Operator-Überladung. Außerdem ist es eine Frechheit dass du nicht mal liest was ich schreibe.

#include <iostream>

class Foo
{
public:
void operator=(const char*) const {
std::cout << "Hello, World!" << std::endl;
}
};

int main()
{
char *pointer = 0;
Foo bar;
bar = pointer;
}Kompilieren und verstehen.

Matrix316[/POST]']Wobei vom Handling und so, ist ja immer noch ein Zeiger. ;)
Ist es nicht.

AnPapaSeiBua
2006-07-26, 16:18:29
Matrix316[/POST]']Was sind denn Zeiger? Was für einen Sinn haben Zeiger? Was für einen Sinn würden Zeiger machen, wenn sie (beim zuweisen) neuen Speicherbereich anlegen und Daten hinkopieren?

Nicht der Zeiger legt einen neuen Speicherbereich an. Das geschieht im überladenen =-Operator (zumindest bei der simpelsten string-Implementierung). Solltest vielleicht mal ein gutes Buch über Objektorientierung lesen (z. B. Effective C++)?

Gast
2006-07-26, 18:04:36
Bei einer Zuweisung std::string foo = "test" wird natürlich aber "std::string &operator=(const char*)" von std::string aufgerufen

Falsch.

Coda
2006-07-26, 18:13:09
Ja falsches Beispiel... std::string foo; foo = "test". Besser?

Ne Begründung wäre trotzdem manchmal ganz nett.

Matrix316
2006-07-26, 21:23:14
Coda[/POST]']Du hast keine Ahnung von Operator-Überladung. Außerdem ist es eine Frechheit dass du nicht mal liest was ich schreibe.


Das einzig relevante was du für mich geschrieben hast war: "Nix Ahnung - raushalten."

Ein Zeiger ist immer noch ein Zeiger und kein Überladener Operator...

Coda[/POST]']

Ist es nicht.

Dann halt ein Objekt der Klasse String, welches einen Zeiger anlegt...

Gast
2006-07-26, 21:52:48
Matrix316[/POST]']Was sind denn Zeiger? Was für einen Sinn haben Zeiger? Was für einen Sinn würden Zeiger machen, wenn sie (beim zuweisen) neuen Speicherbereich anlegen und Daten hinkopieren?das machen ja nicht die Zeiger, sondern die string-Klasse. Genauer gesagt: der für die string-Klasse überladene Zuweisungsoperator. Daß es außerdem noch Implementierungen des Zuweisungsoperators für Zeiger gibt, die tatsächlich nur den Zeiger kopieren und nicht die Daten, steht dazu in keinster Weise im Widerspruch.

char szText[] = "O'zapt is!";
std::string sKopie;
sKopie = szText;

kopiert die Daten.

char szText[] = "O'zapt is!";
char * pcZeiger;
pcZeiger = szText;

kopiert nur den Zeiger.

Coda
2006-07-26, 22:02:50
Matrix316[/POST]']Ein Zeiger ist immer noch ein Zeiger und kein Überladener Operator...
Du kopierst da trotzdem nirgends einen Zeiger sondern die Daten, weil eben "=" überladen ist für std::string. Langsam solltest dus doch kapiert haben oder?

Und das was du am Anfang vom Thread geschrieben hast ist einfach nur "nix Ahnung", vor allem das hier:
Matrix316[/POST]']Überladen mit was? ;)

Anscheinend sind folgende Sachen gleich:

char *test1 = "Hallo"
std::string test2 = "Hallo"

daraus würde ich ableiten, dass, dass ein String Objekt nur ein Zeiger ist.

Wobei test1 = test2 nicht geht, im Gegensatz zu test2 = test1.
Es ist einfach nur grottenfalsch was du da schreibst. Da ist überhaupt nichts gleich und std::string ist auch ganz bestimmt kein Zeiger.

Matrix316[/POST]']Dann halt ein Objekt der Klasse String, welches einen Zeiger anlegt...
"einen Zeiger anlegt"? Was bitte? Es legt Daten auf dem Heap an.

Matrix316
2006-07-26, 22:46:29
Ist ja auch egal:

http://cplus.about.com/od/beginnerctutorial/l/aa051202b.htm The programmer need not be concerned with how or where the string is stored. :rolleyes: ;)

EDIT: Es kann nicht jeder wissen wie die Klasse String aufgebaut ist. :P

Gast
2006-07-27, 21:18:44
gerade das bedeutet aber daß es nicht egal ist: würde string nur eine Kopie des Zeigers enthalten und keine Kopie der Daten anlegen, gerade dann wäre es für den Programmierer wichtig zu wissen wo und wie die Daten gespeichert sind. Er müßte dann nämlich wissen, daß z.B. das hier:

std::string CreateString()
{
char szString[] = "Dieser String existiert nur im Scope dieser Funktion";
std::string sString = szString;

return sString;
}

//...
std::cout << CreateString() << std::endl;

nicht funktionieren könnte, da ein Zeiger auf nur temporär existierende Daten zurückgegeben würde.
Um der Forderung, daß der Programmierer das nicht wissen muß, und es ihm somit ermöglicht sein muß einen Code wie im Beispiel schreiben, nachzukommen, ist es notwendig daß die string-Klasse einen Kopie der Daten anlegt.

Xmas
2006-07-27, 22:33:33
Gast[/POST]']Er müßte dann nämlich wissen, daß z.B. das hier:

std::string CreateString()
{
char szString[] = "Dieser String existiert nur im Scope dieser Funktion";
std::string sString = szString;

return sString;
}

//...
std::cout << CreateString() << std::endl;

nicht funktionieren könnte, da ein Zeiger auf nur temporär existierende Daten zurückgegeben würde.
Stringliterale sind nicht temporär. Ein Pointer auf ein Stringliteral ist für die gesamte Laufzeit des Programmes gültig.

Matrix316
2006-07-29, 17:08:06
Jetzt hab ich mal ne Frage: Kann es sein, dass char x[] und char *x nicht unbedingt gleich sind?

Bei sowas:

char * szText= "O'zapt is!";
char pcZeiger[];
pcZeiger = szText;

Kommt nämlich der Fehler: cannot convert from 'char *' to 'char []'

Umgekehrt
char szText[]= "O'zapt is!";
char *pcZeiger;
pcZeiger = szText;
gehts, aber da scheint das von oben zu stimmen, dass der String nicht übergeben werden kann.

Wobei wenn ich das so mache:

char * CreateString()
{
char * szText= "O'zapt is!";
char * pcZeiger;
pcZeiger = szText;
return pcZeiger;
}

void main()
{
std::cout << CreateString() << std::endl;
}

Funktionierts wunderbar.

Coda
2006-07-29, 17:19:15
Matrix316[/POST]']Jetzt hab ich mal ne Frage: Kann es sein, dass char x[] und char *x nicht unbedingt gleich sind?
Natürlich sind sie im Allgemeinen nicht gleich. Nur als Funktionsargument ist das so.

Trap
2006-07-29, 17:21:09
Ja, char[] und char* unterscheiden sich und zwar ist char[] ein eingeschränkter char*, eingeschränkt in dem Sinne, dass x[0] immer die gleiche Adresse hat wenn x ein char[] ist. Damit ist x=y verboten, ++x, --x und die ganzen Varianten davon auch.

CreateString ist falsch benannt, das erzeugt keinen String, sondern gibt nur einen beim Programmstart bereits existierenden String zurück.

Gast
2006-07-30, 00:20:10
Xmas[/POST]']Stringliterale sind nicht temporär. Ein Pointer auf ein Stringliteral ist für die gesamte Laufzeit des Programmes gültig.ok, dann folgende Variante:

// definiere Typ TString als std::string oder als char*
typedef std::string TString;

char global_string[] = "O'zapft is!";

TString CreateString()
{
char local_copy[64];
sprintf(local_copy, global_string);
// diese Zeile ist interessant:
// TString = std::string -> Daten werden kopiert
// TString = char* -> Zeiger auf lokale Daten wird kopiert
TString return_string = local_copy;

return return_string;
}

Änderst du die Typdefinition von TString von std::string in char* um, wird in der hervorgehobenen Zeile der Zeiger auf einen nur lokal vorhandenen String kopiert.