Forum: PC-Programmierung QString s("Hallo") oder QString s="Hallo" ?


von Stefan F. (Gast)


Lesenswert?

Welche der beiden Schreibweisen aus dem Titel ist besser?

Beide funktionieren, ich frage mich allerdings, ob es gute Gründe für 
die eine oder andere Variante gibt.

Und dann habe ich noch eine kleine Frage: Warum funktioniert die zweite 
Variante? Ich konnte keinen passenden Operator finden:

Zitat von https://doc.qt.io/qt-5/qstring.html:
1
QString &  operator=(const QByteArray &ba)
2
QString &  operator=(QString &&other)
3
QString &  operator=(const QString &other)

Dafür bräuchte man doch einen Operator mit Parameter char* bzw. char[], 
oder irre ich?

von Test (Gast)


Lesenswert?

QString s("Hallo"): Deklaration + gleichzeitige Initialisierung.
QString s="Hallo": Deklaration + gleichzeitige Initialisierung, einfache 
Zuweisung.

Technisch ist das völlig wumpe.

Beitrag #6168053 wurde von einem Moderator gelöscht.
Beitrag #6168054 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Es scheint auch performance-mäßig keinen Unterschied zu machen:
1
warmup...
2
testing...
3
QString s("Hallo"):745ms
4
QString s="Hallo":734ms

von Stefan F. (Gast)


Lesenswert?

Ich habe mir die zweite Frage gerade selbst beantwortet. Der vermisste 
Operator ist doch dokumentiert, nur weiter unten in diesem Block:
1
QString &  operator=(QChar ch)
2
QString &  operator=(QLatin1String str)
3
QString &  operator=(const char *str)
4
QString &  operator=(char ch)

von Dirk K. (merciless)


Lesenswert?

Ändere mal den Code, so dass innerhalb der
Schleife ein Random-String zugewiesen wird.
1
QString s("Hallo");
Ist meiner Meinung nach eine Deklaration
und ein Konstruktoraufruf.
1
QString s = "Hallo";
Ist meiner Meinung nach eine Deklaration,
ein Konstruktoraufruf (links vom '=') sowie
eine Zuweisung (Operator '=');

merciless

von Stefan F. (Gast)


Lesenswert?

Dirk K. schrieb:
> Ändere mal den Code, so dass innerhalb der
> Schleife ein Random-String zugewiesen wird.

Ich fürchte, dann teste ich primär den Zufallsgenerator.

Deine "Meinung" deckt sich mit meiner, deswegen hatte ich erwartet dass 
der zweite Test eindeutig länger dauert. Aber das ist nicht der Fall. 
Bei mehreren Wiederholungen ist er meistens sogar schneller.

von Sven B. (scummos)


Lesenswert?

auto const s = QStringLiteral("Hallo");

von Vincent H. (vinci)


Lesenswert?

Da findet nirgends eine Zuweisung statt. Man könnte operator= löschen 
und der Code würde trotzdem noch funktionieren.

Das das 6 Posts nach Start des Threads immer noch niemand richtig 
beantwortet hat zeigt auf wie sinnvoll Guidelines sind die überall (wos 
geht) Uniform-Initialization vorschlagen...


/edit
Noch lustiger ist dass die falsche Antwort einen Upvote erhalten hat. :)

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Stefan ⛄ F. schrieb:
> Dirk K. schrieb:
>> Ändere mal den Code, so dass innerhalb der
>> Schleife ein Random-String zugewiesen wird.
>
> Ich fürchte, dann teste ich primär den Zufallsgenerator.
>
> Deine "Meinung" deckt sich mit meiner, deswegen hatte ich erwartet dass
> der zweite Test eindeutig länger dauert. Aber das ist nicht der Fall.

Der 2.Fall (=) braucht minimalste länger beim compilieren, da in der AST 
zuerst das "assign" drinsteht und beim optimieren wieder rausfliegt. Ich 
vermute du benutzt GCC oder Clang,  beide sind schlau genug für dieses 
"schwere" optimierungsproblem.

Und selbst wenn nicht und ohne dir zu nahe treten zu wollen: das wird 
nicht das größtes Performance-Problem in deiner Qt-Anwendung sein. ;-)
Zudem

> Bei mehreren Wiederholungen ist er meistens sogar schneller.

Auch da kommen Compiler auf lustige Ideen, wie "Schleifen ausrollen". 
Das geht auch für nur laufzeitbekannte Anzahl Durchläufen. "Duff's 
Device" ist auch bei Optimierern bekannt.

von Stefan F. (Gast)


Lesenswert?

Vincent H. schrieb:
> Da findet nirgends eine Zuweisung statt. Man könnte operator= löschen
> und der Code würde trotzdem noch funktionieren.

Wie kommt dann bei

QString s="Hallo"

die Zeichenkette in s hinein,  wenn das weder eine Zuweisung noch ein 
Aufruf des operator=(char*) ist?

Welcher mir unbekannter Mechanismus steckt dahinter?

von Oliver S. (oliverso)


Lesenswert?

Von jemandem, der C++-Tutorials schreiben will, hätte ich diese Frage 
jetzt nicht erwartet. Das in beiden Fällen der Konstruktor QString(const 
char*) und nicht operator= aufgerufen wird, ist eigentlich Basis 
C++-Wissen.

Oliver

von Vincent H. (vinci)


Lesenswert?

Bitte anschaun ->

CppCon 2018: Nicolai Josuttis “The Nightmare of Initialization in C++”
https://youtu.be/7DTlWPgX6zs

von Stefan F. (Gast)


Lesenswert?

Oliver S. schrieb:
>  Das in beiden Fällen der Konstruktor QString(const
> char*) und nicht operator= aufgerufen wird, ist eigentlich Basis
> C++-Wissen.

Wusste ich noch nicht. Man lernt nie aus.

Offenbar werden Konstruktoren nicht nur zum Initialisieren sondern auch 
zur Typ-Konvertierung verwendet.

Ist das neu?

Ich hatte C++ in den 90er Jahren gelernt und seit dem fast nur in Java 
und C programmiert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Wie kommt dann bei
>
> QString s="Hallo"
>
> die Zeichenkette in s hinein,  wenn das weder eine Zuweisung noch ein
> Aufruf des operator=(char*) ist?

Nimm dir doch einfach den Urgroßvater namens C (hier mal als C99, wegen 
des const-Schlüsselworts):
1
const int i = 42;

Auch wenn das keine wirkliche Konstante ist sondern nur eine 
unveränderbare Variable: durch das "const" kannst du dem "i" niemals 
etwas zuweisen. Damit ist also klar, dass das Ganze keine Zuweisiung 
ist. Es ist syntaktisch eine Definition der Variablen inklusive 
Initialisierung.

Auch wenn du hier nun lesen konntest, dass man bei C++ diese Form nicht 
mehr präferiert, vorhanden ist sie durch die Verwandtschaft mit C (und 
entsprechendem Code in freier Wildbahn, der das so macht) halt immer 
noch.

ps: Natürlich konnte man auch schon immer implizite Typkonvertierungen 
in einer Initialisierung machen. Auch das ist gültiger C-Code:
1
const int i = 3.1415926;

auch, wenn er natürlich sinnlos ist (und mittlerweile die Compiler 
darüber warnen).

Damit sollte sich auch erklären, warum das normale C++-String-Literal in 
einem C++-Initializer auftauchen darf; der Compiler sucht dann den am 
besten passenden Konstruktor dafür.

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Dankeschön. Ich glaube ich habe jetzt genug Stichworte, um die passenden 
Anleitungen zu finden.

von M.K. B. (mkbit)


Lesenswert?

Stefan ⛄ F. schrieb:
> Offenbar werden Konstruktoren nicht nur zum Initialisieren sondern auch
> zur Typ-Konvertierung verwendet.

Ja. Das nennt sich auch konvertierender Konstruktor und ist nichts neues 
in C++. In vielen Fällen merkt man es nicht, weil es sich wie erwartet 
verhält.
Mit explicit kann man auch verhindern, dass die Konvertierung passiert 
ohne dass man es hinschreiben.

https://en.cppreference.com/w/cpp/language/converting_constructor

von Sven B. (scummos)


Lesenswert?

Vincent H. schrieb:
> Das das 6 Posts nach Start des Threads immer noch niemand richtig
> beantwortet hat zeigt auf wie sinnvoll Guidelines sind die überall (wos
> geht) Uniform-Initialization vorschlagen...

Überall uniform initialization zu verwenden ist Quatsch. Die Syntax hat 
ihre Berechtigung, aber int i{3} ist unlesbarer Hipster-Unsinn. Das wird 
sich auch nicht ändern, wenn noch 500 Blogposts darüber geschrieben 
werden.

Die korrekte Antwort ist im übrigen m.E. meine mit dem QStringLiteral, 
denn das ist tatäschlich deutlich schneller als alle anderen Varianten 
...

: Bearbeitet durch User
von C++ Hater (Gast)


Lesenswert?

Vincent H. schrieb:
> Das das 6 Posts nach Start des Threads immer noch niemand richtig
> beantwortet hat zeigt auf wie sinnvoll Guidelines sind die überall (wos
> geht) Uniform-Initialization vorschlagen.

Falsch, denn nach dem erstmaligen Aufruf wird mit [...] = [...]; der 
Zuweisungsoperator aufgeurfen und kein Konstruktor.

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wusste ich noch nicht. Man lernt nie aus.

Und dann schreibst Du C++ Tutorials? Du solltest Dir den Unterschied 
zwischen (Kopier-)Zuweisung und Initialisierung klar machen (s.a. Dein 
Tutorial). Und den Unterschied zwischen Deklaration und Definition. Das 
sind die Basics, die man von einem C++-Tutorial erwartet, was wirklich 
sinnvoll ist.

Das ist ein sog. Typumwandlungskonstruktor. Der wird für implizite 
Typumwandlungen eingesetzt. Es ist üblich den mit "explicit" 
auszuschalten, weil impilizize Tyoumwandlungen meistens unerwünscht sind 
(Du hast Dich ja auch gewundert). Ein Typumwandlungs-ctor ist einer, den 
man mit einem Argument eines fremden Typs aufrufen kann (BTW: nicht nur 
derjenige, der einen Parameter hat).

Es gibt auch das Gegenstück: Typumwandlungsoperatoren. Der bekannteste 
ist wohl operator bool() cosnt. Der sollte immer explicit sein, sonst 
gibt es an unerwarteter Stelle Überraschungen (Übungsaufgabe: warum?).

Auch hier sieht man mal wieder, warum ich uniform-initialization immer 
wieder hier vorschlage, obwohl viele hier im Forum dann ja sofort auf 
die Barrikaden gehen. Das hat schon seinen Grund!

von Stefan F. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Und den Unterschied zwischen Deklaration und Definition. Das
> sind die Basics, die man von einem C++-Tutorial erwartet, was wirklich
> sinnvoll ist.

Nein, das sind Wortklaubereien von möchtegern Deutschlehrern, die dem 
Anfänger keinen praktischen Nutzen bringen.

Ich habe nicht ohne Grund am Ende des Artikels empfohlen, ab da mit 
einem guten Buch weiter zu machen.

Andere Programmiersprachen nutzen die Begriffe übrigens anders als C++, 
was die Sache noch komplizierter macht. Über diese beiden Worte streiten 
sich sogar 50 Jährige Entwickler immer noch - wenn sie nicht imstande 
sind, ihre Jugendzeit hinter sich zu lassen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nein, das sind Wortklaubereien von möchtegern Deutschlehrern, die dem
> Anfänger keinen praktischen Nutzen bringen.

Stefan ⛄ F. schrieb:
> Wilhelm M. schrieb:
>> Und den Unterschied zwischen Deklaration und Definition. Das
>> sind die Basics, die man von einem C++-Tutorial erwartet, was wirklich
>> sinnvoll ist.
>
> Nein, das sind Wortklaubereien von möchtegern Deutschlehrern, die dem
> Anfänger keinen praktischen Nutzen bringen.

Das ist jetzt nicht Dein Ernst, oder?

Google mal nach ODR.

von Stefan F. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Auch hier sieht man mal wieder, warum ich uniform-initialization immer
> wieder hier vorschlage, obwohl viele hier im Forum dann ja sofort auf
> die Barrikaden gehen. Das hat schon seinen Grund!

Erfahrene Entwickler greifen nicht gleich alles auf, was neu ist. Die 
haben auch ihre Gründe.

von Stefan F. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Google mal nach ODR.

"The European Online Dispute Resolution (ODR) platform is provided by 
the European Commission to make online shopping safer and fairer through 
access to quality dispute resolution tools. "

????

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wilhelm M. schrieb:
>> Google mal nach ODR.
>
> "The European Online Dispute Resolution (ODR) platform is provided by
> the European Commission to make online shopping safer and fairer through
> access to quality dispute resolution tools. "
>
> ????

Scheint heute nicht Dein Tag zu sein: mit google klappt's auch nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan ⛄ F. schrieb:
> Erfahrene Entwickler greifen nicht gleich alles auf, was neu ist.

Und Du bist so einer?
In diesem Falle hätte es Dir aber sehr geholfen, wenn Du es richtig 
gelernt hättest bzw. durch die Notation sofort unterscheiden hättest 
können.

Und "neu" ist hierbei ziemlich relativ ...

: Bearbeitet durch User
von Lothar (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Stefan ⛄ F. schrieb:
>> Wilhelm M. schrieb:
>>> Google mal nach ODR.
>>
>> "The European Online Dispute Resolution (ODR) platform is provided by
>> the European Commission to make online shopping safer and fairer through
>> access to quality dispute resolution tools. "
>>
>> ????
>
> Scheint heute nicht Dein Tag zu sein: mit google klappt's auch nicht.

https://de.wikipedia.org/wiki/ODR

Wäre nicht schlecht, wenn du nicht Rätselraten spielen würdest.
Auch wenn es dir Spaß zu machen scheint...

von Wilhelm M. (wimalopaan)


Lesenswert?

Lothar schrieb:
> Wäre nicht schlecht, wenn du nicht Rätselraten spielen würdest.

Ich spiele nicht Rätselraten, sondern ich möchte, dass er was lernt. Und 
das tut er nur, wenn er aktiv wird.

Hätte er statt "ODR" etwa "ODR C++" als Suche bei Google verwendet, wäre 
es der erste(!) Treffer gewesen. Ist das zu schwer?

von Dirk K. (merciless)


Angehängte Dateien:

Lesenswert?

Ausgabe:
1
MyString s("Hallo");
2
-> c'tor with char * parameter called
3
4
MyString s = "Hallo";
5
-> c'tor with char * parameter called
6
7
MyString s;
8
s = "Hallo";
9
-> c'tor w/o parameter called
10
-> operator= with char * parameter called

merciless

von Wilhelm M. (wimalopaan)


Lesenswert?

Dirk K. schrieb:
> Ausgabe:

Falls Du GCC verwendest: _PRETTY_FUNCTION_ macht es einfacher ;-)

von Dirk K. (merciless)


Lesenswert?

Habe hier leider nur VS2019 zur Verfügung.

merciless

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Nein, das sind Wortklaubereien von möchtegern Deutschlehrern

Sind es nicht – wie du ja hier siehst. Gerade bei C++ ist der 
Unterschied zwischen einer Zuweisung und einer Initialisierung u. U. 
gewaltig, da es zwei völlig unterschiedliche Aktionen im Code auslösen 
kann. Insofern sollte man diesen Unterschied sehr wohl verstanden haben, 
auch dann, wenn du diese Wortklauberei ja nicht unbedingt in einem 
Tutorial 1:1 unterbringen musst. Allerdings sollte gerade ein Tutorial 
auf keinen Fall noch mehr Verwirrung in die Begrifflichkeiten bringen, 
indem es an solchen Stellen eben aus Versehen die falschen Worte 
auswählt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dirk K. schrieb:
> Habe hier leider nur VS2019 zur Verfügung.

Hat der schon std::source_location?

: Bearbeitet durch User
von hjnm (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Dirk K. schrieb:
>> Habe hier leider nur VS2019 zur Verfügung.
>
> Hat der schon std::source_location?
Laut
https://stackoverflow.com/questions/4384765/whats-the-difference-between-pretty-function-function-func
ist
1
__FUNCSIG__
 eine Alternative. (Kann ich nicht teste, hier steht nur der GCC zur 
Verfügung.)

von Dirk K. (merciless)


Lesenswert?

Wilhelm M. schrieb:
> Dirk K. schrieb:
>> Habe hier leider nur VS2019 zur Verfügung.
>
> Hat der schon std::source_location?
Nein, da nur C++17, source_location gibt es wohl ab C++20.


hjnm schrieb:
> Laut
> 
https://stackoverflow.com/questions/4384765/whats-the-difference-between-pretty-function-function-func
> ist
1
__FUNCSIG__
> eine Alternative.

Das funktioniert.

merciless

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
> Allerdings sollte gerade ein Tutorial
> auf keinen Fall noch mehr Verwirrung in die Begrifflichkeiten bringen,
> indem es an solchen Stellen eben aus Versehen die falschen Worte
> auswählt.

Wo ist es denn falsch?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:

> Wo ist es denn falsch?

Habe ich nicht behauptet, ich habe nur festgestellt, dass es mehr als 
nur "Krümelkackerei" ist, die richtigen Begriffe zumindest zu kennen, 
wenn man anderen etwas beibringen möchte.

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
>> Wo ist es denn falsch?
> Habe ich nicht behauptet

Ich würde mich dennoch über konkrete Korrekturhinweise freuen, denn 
damit kann ich im Interesse der armen Leser mehr anfangen, als mit 
persönlicher Kritik.

Das geht auch an Wilhelm M.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Prinzipiell OK, allerdings ist es natürlich nicht so ganz kurz, und ich 
fürchte, für ein vernünftiges Review fehlt mir gerade die Zeit.

Kurz mal drüber geschaut: im Abschnitt "Variablen" sprichst du von einer 
Deklaration, wobei es tatsächlich um eine Definition geht – die zwar 
zugleich auch deklarative Wirkung hat (d.h. ab da ist sie dem Compiler 
innerhalb dieses Sichtbarkeitsbereichs bekannt), aber die Definition 
steht hier im Vordergrund.

Unterschied: deklarieren kannst du mehrmals; das macht dem Compiler 
etwas bekannt. Oft erfolgt das über eine Header-Datei. Definieren sollte 
man nur einmal ¹), an dieser Stelle wird das Objekt tatsächlich erzeugt 
und ggf. auch initialisiert.

¹) Historisch in C konnte man globale Definitionen, die keine 
Initialisierungen haben (.bss section) auch in mehreren Modulen haben. 
Diese wurden dann vom Linker miteinander überlagert. Das ist eine 
Remineszenz an FORTRANs COMMON-Blöcke, die zwar vom C-Standard als 
mögliche Option abgesegnet ist, aber aus heutiger Sicht außerordentlich 
schlechter Programmierstil, den man meiden sollte.

von Stefan F. (Gast)


Lesenswert?

Jörg W. schrieb:
> Kurz mal drüber geschaut: im Abschnitt "Variablen" sprichst du von einer
> Deklaration, wobei es tatsächlich um eine Definition geht

Danke Jörg

von Rolf M. (rmagnus)


Lesenswert?

Dirk K. schrieb:
> MyString s("Hallo");
> -> c'tor with char * parameter called
>
> MyString s = "Hallo";
> -> c'tor with char * parameter called

Es gibt einen wichtigen Unterschied zwischen diesen beiden, aber laut 
gcc wohl nur bis C++14. Die zweite Variante braucht den Copy-Contruktor, 
auch wenn er ggf. gar nicht aufgerufen wird.

von Oliver S. (oliverso)


Lesenswert?

Rolf M. schrieb:
> Es gibt einen wichtigen Unterschied zwischen diesen beiden, aber laut
> gcc wohl nur bis C++14.

Laut Standard auch. Copy elision ist (für den Fall) erst ab C++17 
garantiert. Warum allerdings gcc den copy-Konstruktor in vorherigen 
Sprachstandards sehen will, obwohl er offensichtlich doch copy elision 
macht, kein Ahnung.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> Laut Standard auch. Copy elision ist (für den Fall) erst ab C++17
> garantiert. Warum allerdings gcc den copy-Konstruktor in vorherigen
> Sprachstandards sehen will, obwohl er offensichtlich doch copy elision
> macht, kein Ahnung.

Weil das im Sprachstandard so vorgeschrieben ist. Der Compiler darf zwar 
das Kopieren des Objekts wegoptimieren, aber da sich die Validität von 
Code nicht abhängig von Optimierungseinstellungen ändern darf, muss ein 
Copy-Konstruktor trotzdem verfügbar sein, auch wenn er am Ende gar nicht 
aufgerufen wird.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.