QString -> char*

Du bist neu in der Welt von C++? Dann schau hier herein!
Antworten
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

QString -> char*

Beitrag von cooky1976 »

Hallo,

ich muss einen QString in einen char* wandeln, dachte zuerst, dass das on-the-fly gehen sollte, aber da gibt es keine Methode ... nur über Umwege:

Code: Alles auswählen

#include <iostream>
#include <QString>
#include <QChar>
#include <QByteArray>

int main(int argc, char **argv)
{
	QString test = "Test";
	
	QByteArray test3 = test.toAscii();
	char* test2 = ((QByteArray)test.toAscii()).data();
	char* test4 = test3.data();

	std::cout << test4 << std::endl;
}
Warum funktioniert der Code in einer Zeile nicht? Ich bekomme da immer einen Fehler. Ich kann das leider nicht wirklich nachvollziehen, da das in anderen Programmiersprachen ohne Probleme funktioniert?

Über jeden Hinweis bin ich dankbar.

Gute Nacht

Alexander

Nachtrag:
ich habe diesesn Thread gefunden:http://qtforum.de/forum/viewtopic.php?t ... tring+char. Heisst das dann für mich, dass ich in C++ nie mehrere Methoden hintereinander schachteln kann, wenn darin mehrere Objekttypen verwendet werden? Und daraus folgend, dass ich jedes Mal ein Temporärobjekt anlegen muss ....
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Nein, das heißt es nicht. Solange am Ende ein Objekt rauskommt ist alles ok.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

Beitrag von cooky1976 »

Ah, ok, das heisst also in meinem Falle ist das Problem der Pointer auf char, richtig?

Schönen Sonntag

Alexander
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Dein Problem ist die lebensdauer des implizieten objectes .....
char* test2 = ((QByteArray)test.toAscii()).data();
was machst du da genau ....
von links nach rechts

- test.toAscii() liefert dir ein QByteArray zurueck. dieses Object ist temporaer, gilt also nur fuer die Zeit des aufrufes !

Anmerkung: der cast (QByteArray) ist 1. unnötig, und 2. schlechter style, da C-Cast in C++ immer boese ist !

- .data() liefert den Zeiger auf die interne Datenfolge des QByteArrays zurueck. Wir erinnern uns: Das QByteArray ist temporaer.

- char* test2 = du weisst diesen Zeiger einer Variable fuer solche zeichenketten zu. Wir erinnern uns: Das QByteArray ist temporaer.

Bis jetzt noch alles ok.

Doch genau eine Zeile spaeter, bzw genau nach dem Semikolion fuers ende der anweisung, nimmt dein Problem gestalt an!

Das QByteArray, als temporaeres uebergabeobject, hat seine Pflicht erfuellt, und wird wieder freigegeben
deine variable test2 zeigt aber immer noch auf die internen daten dieses Objects, nachdem es nicht mehr existiert, genau ins Nirwana !
damit ist test2 ne tickende zeitbombe in deinem code ^^ sprich verhalten undefiniert .... und kann alles kaputtmachen wenn du drauf zugreifst, und je nachdem was das program da mal wieder hinlegt, auf den speicher ...

Problem nu verstanden ?

Ciao ...
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

Beitrag von cooky1976 »

Ja, irgendwie war mir das schon klar, als ich den anderen Thread gelesen hatte. Frage .... wir würde es klappen, ohne dass ich noch ein eigenes QByteArray-Objekt benötige. Gibt es da eine Chancce?

Also nach meinem Verständnis nicht, da ich ja das QByteArray-Objekt benötige, aus dem ich das "data" lese. Liege ich richtig?

Danke schon mal

Alexander
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

ohne dass ich noch ein eigenes QByteArray-Objekt benötige.
Ein definitives Jein ....
QByteArray QString::toAscii () const

Allein schon das vorhandensein dieser Funktion gibt zu verstehen, das die "Daten" nicht in ASCII vorliegen, sondern in irgend was anderen, bzw das du dich auf das vorhandensein der Daten im Ascii format nicht verlassen kann.
Liest man die Doku, weiss man, das die Daten als Unicode vorliegen, und impliziet shared sind, also ein direkter zugriff darauf ned so einfach ist, bzw sowieso das falsche format liefert.

Deshalb wirst du um einen eigenen "Holder" fuer die Daten ned drumherumkommen.Dein char* zeiger ist ja nur ein Zeiger dessen "Inhalt" du ja irgendwie verwalten musst.

DU koenntest alles selber haendisch machen, aber das waer schlechtes C++, weil vorhandene Klassen dann besser verwendet werden sollten.

Unter QT bietet sich das QByteArray halt an ... warum es nicht nutzen ?
Warum statt der Zeigervariable ned das QByteArry selber nehmen ?

Und ueberall wo du die zeichenkette brauchst, die entsprechnde funktion aufzurufen.

Code: Alles auswählen

   
   QString test = "Test";
   
   QByteArray strAscii = test.toAscii();
   std::cout << strAscii.data() << std::endl; 
Waer nen saueberer schneller und performanter Weg ....

Wenn Du QByteArray ned magst, gibt es natuerlich andere Alternativen.
C++ gibt es fuer Ascii Strings den std::string als container.

Als erstes wuerde man vielleicht folgendes Schreiben:

Code: Alles auswählen

   
   QString test = "Test";
   
   std::string strAscii = test.toAscii().data();
   std::cout << strAscii.c_string() << std::endl; 
Das wuerde funktionieren, ist aber boese unperformant.
- test.toAscii() erzeugt das temp. Object und transformiert die Daten da rein.
- der Konstruktor von std::string kopiert die als const char * uebergebene zeichenkette und verwaltet die dann.

Man hat also 2 mal speicher reserviert fuer das ergebnis, und einmal gleich wieder freigegeben.

Zum Glueck mag Trolltech die C++ Programmierer, und der QString bietet auch ein
std::string QString::toStdString () const
an.

Code: Alles auswählen

   
   QString test = "Test";
   
   std::string strAscii = test.toStdString();
   std::cout << strAscii.c_str() << std::endl; // Besser : std::cout << strAscii << std::endl; weil std::ostream den std:string nativ unterstuetz. 
Warum iss das Performanter, mal abgesehen davon das es schoener aussieht ?
Eigentlich muesste der Compiler ja zuerst das Temp std::string object erzeugen, und dieses dann deiner selbst angelegten variable zuweissen. Die zuweisung sollte doch auch kopieren. Damit haettest genau so 2 mal speicher erzeugt und einmal gleich wieder freigegeben.

Das Zauberwort heisst "Return Value Optimization" und die meisten compiler koennen dies.
Das heisst der Compiler erkennt, das das temporaere rueckgabeobject gleich einer neuen variablen des selben Types zugewiesen wird, und erzeugt die spart sich die kopie in dem er gleich die temporaere Variable als die erzeugte weitergibt.

Ob du QByteArray oder std:string verwendest, iss in dem fall deine entscheidung.
Ohne Den Holder kommst aber ned aus !

Noch mehr machen kann man schon, aber da muss man auch mehr in Frage stellen, z.b. den QString selber !

Wer erzeugt den QString, und muss es wirklich ein QString sein ? Meist bekommt man nen C-String und convertiert den in nen QString, um den dann wieder zurueck in nen C-String zu verwandeln.

Code: Alles auswählen

   
   QByteArray test = "Test";
   
   std::cout << test.data() << std::endl; 
iss natuerlich noch effizienter :-)

Ciao ...
rf
Beiträge: 5
Registriert: 17. August 2010 14:58

Beitrag von rf »

*thread aus dem grab hol

Danke RHBaum, für deine ausführlichen Erläuterungen!
Use references when you can, and pointers when you have to.
Uncopy
Beiträge: 20
Registriert: 26. August 2010 16:20
Wohnort: Berlin

Beitrag von Uncopy »

Wie ich gerade gesehen habe, hat jemand einen Artikel dazu im Wiki verfasst:

http://www.qtwiki.de/wiki/QString_nach_char-Pointer

...nachdem ich ihn ein wenig überarbeitet hatte, war mir so, als wäre die Temporäres-Objekt-Problematik in einem eigenen Artikel vielleicht besser aufgehoben. Was meint ihr?

Gibt's Bedarf für eine ausführliche verständliche Darstellung dieses spannenden C++-Themas?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

selbe Problem wie hier: http://doc.qt.nokia.com/4.7-snapshot/qt ... qPrintable


Kann man zwar so nutzen

Code: Alles auswählen

QString hallo("Hallo");
std::cout << qPrintable(hallo);
aber halt nicht so

Code: Alles auswählen

QString hallo("Hallo");
const char * hallo2 = qPrintable(hallo);
std::cout << hallo2;
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Uncopy
Beiträge: 20
Registriert: 26. August 2010 16:20
Wohnort: Berlin

Beitrag von Uncopy »

padreigh hat geschrieben:selbe Problem wie hier: http://doc.qt.nokia.com/4.7-snapshot/qt ... qPrintable


Kann man zwar so nutzen

Code: Alles auswählen

QString hallo("Hallo");
std::cout << qPrintable(hallo);
aber halt nicht so

Code: Alles auswählen

QString hallo("Hallo");
const char * hallo2 = qPrintable(hallo);
std::cout << hallo2;
Damit ist qPrintable() also als Adapter-Muffe für bestimmte Funktionsaufrufe aufzufassen.
Trivial ist diese Problematik keineswegs: sie wird viel zu oft nicht erkannt (oder ist einfach unbekannt). Und so kommt es, dass Laien Fehler einbauen, die auch vom Fachmann leicht übersehen werden.

...nach einen C-style Cast kann man jedenfalls leichter suchen als nach hängenden Referenzen auf Eigenschaften temporärer Objekte. ;-)
Antworten